You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/09/25 12:32:25 UTC
[27/34] syncope git commit: [SYNCOPE-1369] Flowable support
refactored as extension + code review (now with variable cleanup)
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
new file mode 100644
index 0000000..e16f5c2
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
@@ -0,0 +1,355 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.approvals;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.DirectoryDataProvider;
+import org.apache.syncope.client.console.panels.DirectoryPanel;
+import org.apache.syncope.client.console.rest.UserRequestRestClient;
+import org.apache.syncope.client.console.approvals.ApprovalDirectoryPanel.ApprovalProvider;
+import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.client.console.widgets.ApprovalsWidget;
+import org.apache.syncope.client.console.wizards.AjaxWizard;
+import org.apache.syncope.client.console.wizards.any.AnyWrapper;
+import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
+import org.apache.syncope.common.lib.AnyOperations;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.patch.PasswordPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.ProvisioningResult;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.FlowableEntitlement;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+
+public class ApprovalDirectoryPanel
+ extends DirectoryPanel<UserRequestForm, UserRequestForm, ApprovalProvider, UserRequestRestClient> {
+
+ private static final long serialVersionUID = -7122136682275797903L;
+
+ protected final BaseModal<UserRequestForm> manageApprovalModal = new BaseModal<UserRequestForm>("outer") {
+
+ private static final long serialVersionUID = 389935548143327858L;
+
+ @Override
+ protected void onConfigure() {
+ super.onConfigure();
+ addSubmitButton();
+ size(Modal.Size.Large);
+ }
+
+ };
+
+ public ApprovalDirectoryPanel(final String id, final PageReference pageReference) {
+ super(id, pageReference, true);
+ disableCheckBoxes();
+ setFooterVisibility(false);
+ modal.size(Modal.Size.Large);
+
+ addOuterObject(manageApprovalModal);
+
+ manageApprovalModal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+ private static final long serialVersionUID = 8804221891699487139L;
+
+ @Override
+ public void onClose(final AjaxRequestTarget target) {
+ updateResultTable(target);
+
+ Serializable widget = SyncopeConsoleSession.get().getAttribute(ApprovalsWidget.class.getName());
+ if (widget instanceof ApprovalsWidget) {
+ ((ApprovalsWidget) widget).refreshLatestAlerts(target);
+ }
+
+ manageApprovalModal.show(false);
+ }
+ });
+
+ restClient = new UserRequestRestClient();
+
+ initResultTable();
+
+ MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, FlowableEntitlement.WORKFLOW_FORM_SUBMIT);
+ }
+
+ @Override
+ protected List<IColumn<UserRequestForm, String>> getColumns() {
+ List<IColumn<UserRequestForm, String>> columns = new ArrayList<>();
+
+ columns.add(new PropertyColumn<>(
+ new ResourceModel("taskId"), "taskId", "taskId"));
+ columns.add(new PropertyColumn<>(
+ new ResourceModel("key"), "formKey", "formKey"));
+ columns.add(new PropertyColumn<>(
+ new ResourceModel("username"), "username"));
+ columns.add(new DatePropertyColumn<>(
+ new ResourceModel("createTime"), "createTime", "createTime"));
+ columns.add(new DatePropertyColumn<>(
+ new ResourceModel("dueDate"), "dueDate", "dueDate"));
+ columns.add(new PropertyColumn<>(
+ new ResourceModel("owner"), "owner", "owner"));
+
+ return columns;
+ }
+
+ @Override
+ public ActionsPanel<UserRequestForm> getActions(final IModel<UserRequestForm> model) {
+ final ActionsPanel<UserRequestForm> panel = super.getActions(model);
+
+ panel.add(new ActionLink<UserRequestForm>() {
+
+ private static final long serialVersionUID = -3722207913631435501L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
+ claimForm(model.getObject().getTaskId());
+ SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+ ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+ target.add(container);
+ }
+ }, ActionLink.ActionType.CLAIM, FlowableEntitlement.WORKFLOW_FORM_CLAIM);
+
+ panel.add(new ActionLink<UserRequestForm>() {
+
+ private static final long serialVersionUID = -3722207913631435501L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
+ manageApprovalModal.setFormModel(new CompoundPropertyModel<>(model.getObject()));
+
+ target.add(manageApprovalModal.setContent(
+ new ApprovalModal(manageApprovalModal, pageRef, model.getObject()) {
+
+ private static final long serialVersionUID = 5546519445061007248L;
+
+ @Override
+ public void onSubmit(final AjaxRequestTarget target) {
+ try {
+ super.onSubmit(target);
+
+ ApprovalDirectoryPanel.this.getTogglePanel().close(target);
+ } catch (SyncopeClientException e) {
+ SyncopeConsoleSession.get().error(getString(Constants.ERROR) + ": " + e.getMessage());
+ }
+ ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+ }
+
+ }));
+
+ manageApprovalModal.header(new Model<>(getString("approval.manage", new Model<>(model.getObject()))));
+ manageApprovalModal.show(true);
+ }
+
+ @Override
+ protected boolean statusCondition(final UserRequestForm modelObject) {
+ return SyncopeConsoleSession.get().getSelfTO().getUsername().
+ equals(model.getObject().getOwner());
+ }
+
+ }, ActionLink.ActionType.MANAGE_APPROVAL, FlowableEntitlement.WORKFLOW_FORM_READ);
+
+ // SYNCOPE-1200 edit user while in approval state
+ panel.add(new ActionLink<UserRequestForm>() {
+
+ private static final long serialVersionUID = -3722207913631435501L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
+ modal.setFormModel(new CompoundPropertyModel<>(model.getObject()));
+
+ UserRequestForm formTO = model.getObject();
+ UserTO newUserTO;
+ UserTO previousUserTO;
+ if (formTO.getUserPatch() == null) {
+ newUserTO = formTO.getUserTO();
+ previousUserTO = null;
+ } else if (formTO.getUserTO() == null) {
+ // make it stronger by handling possible NPE
+ previousUserTO = new UserTO();
+ previousUserTO.setKey(formTO.getUserPatch().getKey());
+ newUserTO = AnyOperations.patch(previousUserTO, formTO.getUserPatch());
+ } else {
+ previousUserTO = formTO.getUserTO();
+ formTO.getUserTO().setKey(formTO.getUserPatch().getKey());
+ formTO.getUserTO().setPassword(null);
+ newUserTO = AnyOperations.patch(formTO.getUserTO(), formTO.getUserPatch());
+ }
+
+ AjaxWizard.EditItemActionEvent<UserTO> editItemActionEvent =
+ new AjaxWizard.EditItemActionEvent<>(newUserTO, target);
+ editItemActionEvent.forceModalPanel(new ApprovalUserWizardBuilder(
+ model.getObject(),
+ previousUserTO,
+ newUserTO,
+ new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses(),
+ FormLayoutInfoUtils.fetch(Collections.singletonList(AnyTypeKind.USER.name())).getLeft(),
+ pageRef
+ ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT));
+
+ send(ApprovalDirectoryPanel.this, Broadcast.EXACT, editItemActionEvent);
+ }
+
+ @Override
+ protected boolean statusCondition(final UserRequestForm modelObject) {
+ return SyncopeConsoleSession.get().getSelfTO().getUsername().
+ equals(model.getObject().getOwner());
+ }
+
+ }, ActionLink.ActionType.EDIT_APPROVAL, FlowableEntitlement.WORKFLOW_FORM_SUBMIT);
+
+ return panel;
+ }
+
+ @Override
+ protected ApprovalProvider dataProvider() {
+ return new ApprovalProvider(rows);
+ }
+
+ @Override
+ protected String paginatorRowsKey() {
+ return Constants.PREF_WORKFLOW_FORM_PAGINATOR_ROWS;
+ }
+
+ public static class ApprovalProvider extends DirectoryDataProvider<UserRequestForm> {
+
+ private static final long serialVersionUID = -2311716167583335852L;
+
+ private final UserRequestRestClient restClient = new UserRequestRestClient();
+
+ public ApprovalProvider(final int paginatorRows) {
+ super(paginatorRows);
+
+ setSort("createTime", SortOrder.ASCENDING);
+ }
+
+ @Override
+ public Iterator<UserRequestForm> iterator(final long first, final long count) {
+ int page = ((int) first / paginatorRows);
+ return restClient.getForms((page < 0 ? 0 : page) + 1, paginatorRows, getSort()).iterator();
+ }
+
+ @Override
+ public long size() {
+ return restClient.countForms();
+ }
+
+ @Override
+ public IModel<UserRequestForm> model(final UserRequestForm form) {
+ return new IModel<UserRequestForm>() {
+
+ private static final long serialVersionUID = -2566070996511906708L;
+
+ @Override
+ public UserRequestForm getObject() {
+ return form;
+ }
+ };
+ }
+ }
+
+ @Override
+ protected Collection<ActionLink.ActionType> getBatches() {
+ return Collections.<ActionLink.ActionType>emptyList();
+ }
+
+ private void claimForm(final String taskId) {
+ try {
+ restClient.claimForm(taskId);
+ } catch (SyncopeClientException scee) {
+ SyncopeConsoleSession.get().error(getString(Constants.ERROR) + ": " + scee.getMessage());
+ }
+ }
+
+ private class ApprovalUserWizardBuilder extends UserWizardBuilder {
+
+ private static final long serialVersionUID = 1854981134836384069L;
+
+ private final UserRequestForm formTO;
+
+ ApprovalUserWizardBuilder(
+ final UserRequestForm formTO,
+ final UserTO previousUserTO,
+ final UserTO userTO,
+ final List<String> anyTypeClasses,
+ final UserFormLayoutInfo formLayoutInfo,
+ final PageReference pageRef) {
+
+ super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, pageRef);
+ this.formTO = formTO;
+ }
+
+ @Override
+ protected Serializable onApplyInternal(final AnyWrapper<UserTO> modelObject) {
+ UserTO inner = modelObject.getInnerObject();
+
+ ProvisioningResult<UserTO> result;
+
+ UserPatch patch = AnyOperations.diff(inner, formTO.getUserTO(), false);
+
+ if (StringUtils.isNotBlank(inner.getPassword())) {
+ PasswordPatch passwordPatch = new PasswordPatch.Builder().
+ value(inner.getPassword()).onSyncope(true).resources(inner.
+ getResources()).
+ build();
+ patch.setPassword(passwordPatch);
+ }
+ // update just if it is changed
+ if (patch.isEmpty()) {
+ result = new ProvisioningResult<>();
+ result.setEntity(inner);
+ } else {
+ result = userRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
+ UserRequestForm workFlowTO = restClient.getForms(result.getEntity().getKey()).get(0);
+ if (workFlowTO != null) {
+ claimForm(workFlowTO.getTaskId());
+ }
+ }
+
+ return result;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
new file mode 100644
index 0000000..0cae1c8
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.approvals;
+
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.rest.UserRequestRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.syncope.client.console.panels.SubmitableModalPanel;
+import org.apache.syncope.client.console.panels.WizardModalPanel;
+
+public class ApprovalModal extends Panel implements SubmitableModalPanel, WizardModalPanel<UserRequestForm> {
+
+ private static final long serialVersionUID = -8847854414429745216L;
+
+ private final UserRequestRestClient restClient = new UserRequestRestClient();
+
+ private final BaseModal<?> modal;
+
+ private final UserRequestForm formTO;
+
+ private final PageReference pageRef;
+
+ public ApprovalModal(final BaseModal<?> modal, final PageReference pageRef, final UserRequestForm formTO) {
+ super(BaseModal.CONTENT_ID);
+ this.modal = modal;
+ this.formTO = formTO;
+ this.pageRef = pageRef;
+
+ MultilevelPanel mlp = new MultilevelPanel("approval");
+ mlp.setFirstLevel(new Approval(pageRef, formTO) {
+
+ private static final long serialVersionUID = -2195387360323687302L;
+
+ @Override
+ protected void viewDetails(final AjaxRequestTarget target) {
+ mlp.next(getString("approval.details"), new ApprovalDetails(pageRef, formTO), target);
+ }
+ });
+ add(mlp);
+ }
+
+ @Override
+ public void onSubmit(final AjaxRequestTarget target) {
+ this.restClient.submitForm(formTO);
+ this.modal.show(false);
+ this.modal.close(target);
+ SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+ }
+
+ @Override
+ public void onError(final AjaxRequestTarget target) {
+ ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+ }
+
+ @Override
+ public UserRequestForm getItem() {
+ return this.formTO;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Approvals.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Approvals.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Approvals.java
new file mode 100644
index 0000000..0dbc4db
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Approvals.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
+import org.apache.syncope.client.console.approvals.ApprovalDirectoryPanel;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+public class Approvals extends BasePage {
+
+ private static final long serialVersionUID = -1100228004207271271L;
+
+ public Approvals(final PageParameters parameters) {
+ super(parameters);
+
+ body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
+
+ WebMarkupContainer content = new WebMarkupContainer("content");
+ content.setOutputMarkupId(true);
+ body.add(content);
+
+ content.add(new ApprovalDirectoryPanel("wfPanel", getPageReference()));
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java
new file mode 100644
index 0000000..562aad1
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.annotations.ExtPage;
+import org.apache.syncope.client.console.panels.BpmnProcessDirectoryPanel;
+import org.apache.syncope.client.console.wizards.WizardMgtPanel;
+import org.apache.syncope.common.lib.to.BpmnProcessTO;
+import org.apache.syncope.common.lib.types.FlowableEntitlement;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+@ExtPage(label = "Flowable", icon = "fa-briefcase",
+ listEntitlement = FlowableEntitlement.BPMN_PROCESS_LIST, priority = 200)
+public class Flowable extends BaseExtPage {
+
+ private static final long serialVersionUID = -8781434495150074529L;
+
+ public Flowable(final PageParameters parameters) {
+ super(parameters);
+
+ body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
+
+ WebMarkupContainer content = new WebMarkupContainer("content");
+ content.setOutputMarkupId(true);
+ body.add(content);
+
+ WebMarkupContainer disabled = new WebMarkupContainer("disabled");
+ disabled.setOutputMarkupPlaceholderTag(true);
+ content.add(disabled);
+
+ WizardMgtPanel<BpmnProcessTO> bpmnProcessesPanel = new BpmnProcessDirectoryPanel.Builder(getPageReference()) {
+
+ private static final long serialVersionUID = -5960765294082359003L;
+
+ }.disableCheckBoxes().build("bpmnProcessesPanel");
+ bpmnProcessesPanel.setOutputMarkupPlaceholderTag(true);
+ MetaDataRoleAuthorizationStrategy.authorize(bpmnProcessesPanel, ENABLE, FlowableEntitlement.BPMN_PROCESS_LIST);
+
+ content.add(bpmnProcessesPanel);
+
+ if (SyncopeConsoleSession.get().getPlatformInfo().getUserWorkflowAdapter().contains("Flowable")) {
+ disabled.setVisible(false);
+ } else {
+ bpmnProcessesPanel.setVisible(false);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/FlowableModelerPopupPage.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/FlowableModelerPopupPage.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/FlowableModelerPopupPage.java
new file mode 100644
index 0000000..b55d2b5
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/FlowableModelerPopupPage.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import org.apache.wicket.markup.html.WebPage;
+
+public class FlowableModelerPopupPage extends WebPage {
+
+ private static final long serialVersionUID = -7031206743629422898L;
+
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/BpmnProcessDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/BpmnProcessDirectoryPanel.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/BpmnProcessDirectoryPanel.java
new file mode 100644
index 0000000..b7914bb
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/BpmnProcessDirectoryPanel.java
@@ -0,0 +1,308 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import javax.ws.rs.core.MediaType;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.DirectoryDataProvider;
+import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.pages.ModelerPopupPage;
+import org.apache.syncope.client.console.panels.BpmnProcessDirectoryPanel.BpmProcessDataProvider;
+import org.apache.syncope.client.console.rest.BpmnProcessRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.ImageModalPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.XMLEditorPanel;
+import org.apache.syncope.client.console.wizards.AjaxWizardBuilder;
+import org.apache.syncope.client.console.wizards.WizardMgtPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.BpmnProcessTO;
+import org.apache.syncope.common.lib.types.FlowableEntitlement;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.extensions.wizard.WizardModel;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+import org.apache.wicket.util.io.IOUtils;
+
+public class BpmnProcessDirectoryPanel extends DirectoryPanel<
+ BpmnProcessTO, BpmnProcessTO, BpmProcessDataProvider, BpmnProcessRestClient> {
+
+ private static final long serialVersionUID = 2705668831139984998L;
+
+ private static final String FLOWABLE_MODELER_CTX = "flowable-modeler";
+
+ private final BaseModal<String> utility;
+
+ protected BpmnProcessDirectoryPanel(final String id, final Builder builder) {
+ super(id, builder);
+
+ this.addNewItemPanelBuilder(new AjaxWizardBuilder<BpmnProcessTO>(new BpmnProcessTO(), pageRef) {
+
+ private static final long serialVersionUID = 1633859795677053912L;
+
+ @Override
+ protected WizardModel buildModelSteps(
+ final BpmnProcessTO modelObject, final WizardModel wizardModel) {
+
+ return wizardModel;
+ }
+ }, false);
+ NewBpmnProcess newBpmnProcess = new NewBpmnProcess("newBpmnProcess", container, pageRef);
+ addInnerObject(newBpmnProcess);
+ AjaxLink<Void> newBpmnProcessLink = new AjaxLink<Void>("add") {
+
+ private static final long serialVersionUID = -7978723352517770644L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target) {
+ newBpmnProcess.toggle(target, true);
+ }
+ };
+ ((WebMarkupContainer) get("container:content")).addOrReplace(newBpmnProcessLink);
+
+ setShowResultPage(true);
+
+ modal.size(Modal.Size.Large);
+
+ utility = new BaseModal<>("outer");
+ addOuterObject(utility);
+ utility.size(Modal.Size.Large);
+ AjaxSubmitLink xmlEditorSubmit = utility.addSubmitButton();
+ MetaDataRoleAuthorizationStrategy.authorize(xmlEditorSubmit, RENDER, FlowableEntitlement.BPMN_PROCESS_SET);
+ utility.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+ private static final long serialVersionUID = 8804221891699487139L;
+
+ @Override
+ public void onClose(final AjaxRequestTarget target) {
+ utility.show(false);
+ utility.close(target);
+ }
+ });
+ initResultTable();
+ }
+
+ @Override
+ protected BpmProcessDataProvider dataProvider() {
+ return new BpmProcessDataProvider(rows);
+ }
+
+ @Override
+ protected String paginatorRowsKey() {
+ return Constants.PREF_WORKFLOW_PAGINATOR_ROWS;
+ }
+
+ @Override
+ protected List<IColumn<BpmnProcessTO, String>> getColumns() {
+ List<IColumn<BpmnProcessTO, String>> columns = new ArrayList<>();
+
+ columns.add(new PropertyColumn<>(new ResourceModel("key"), "key"));
+ columns.add(new PropertyColumn<>(new ResourceModel("name"), "name", "name"));
+
+ return columns;
+ }
+
+ @Override
+ public ActionsPanel<BpmnProcessTO> getActions(final IModel<BpmnProcessTO> model) {
+ final ActionsPanel<BpmnProcessTO> panel = super.getActions(model);
+
+ panel.add(new ActionLink<BpmnProcessTO>() {
+
+ private static final long serialVersionUID = -184018732772021627L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final BpmnProcessTO ignore) {
+ final IModel<String> wfDefinition = new Model<>();
+ try {
+ wfDefinition.setObject(IOUtils.toString(restClient.getDefinition(
+ MediaType.APPLICATION_XML_TYPE, model.getObject().getKey())));
+ } catch (IOException e) {
+ LOG.error("Could not get workflow definition", e);
+ }
+
+ utility.header(Model.of(model.getObject().getKey()));
+ utility.setContent(new XMLEditorPanel(utility, wfDefinition, false, pageRef) {
+
+ private static final long serialVersionUID = -7688359318035249200L;
+
+ @Override
+ public void onSubmit(final AjaxRequestTarget target) {
+ if (StringUtils.isNotBlank(wfDefinition.getObject())) {
+ try {
+ restClient.setDefinition(MediaType.APPLICATION_XML_TYPE,
+ model.getObject().getKey(), wfDefinition.getObject());
+ SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+
+ target.add(container);
+ utility.show(false);
+ utility.close(target);
+ } catch (SyncopeClientException e) {
+ SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
+ ? e.getClass().getName() : e.getMessage());
+ }
+ ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+ }
+ }
+ });
+ utility.show(target);
+ target.add(utility);
+ }
+ }, ActionLink.ActionType.EDIT, FlowableEntitlement.BPMN_PROCESS_SET);
+
+ panel.add(new ActionLink<BpmnProcessTO>() {
+
+ private static final long serialVersionUID = 3109256773218160485L;
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final BpmnProcessTO ignore) {
+ modal.header(Model.of(model.getObject().getKey()));
+ modal.setContent(new ImageModalPanel<>(
+ modal, restClient.getDiagram(model.getObject().getKey()), pageRef));
+ modal.show(target);
+ target.add(modal);
+ }
+ }, ActionLink.ActionType.VIEW, FlowableEntitlement.BPMN_PROCESS_GET);
+
+ panel.add(new ActionLink<BpmnProcessTO>() {
+
+ private static final long serialVersionUID = -184018732772021627L;
+
+ @Override
+ public Class<? extends Page> getPageClass() {
+ return ModelerPopupPage.class;
+ }
+
+ @Override
+ public PageParameters getPageParameters() {
+ PageParameters parameters = new PageParameters();
+ parameters.add(Constants.MODELER_CONTEXT, FLOWABLE_MODELER_CTX);
+ parameters.add(Constants.MODEL_ID_PARAM, model.getObject().getModelId());
+
+ return parameters;
+ }
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final BpmnProcessTO ignore) {
+ // do nothing
+ }
+ }, ActionLink.ActionType.EXTERNAL_EDITOR, FlowableEntitlement.BPMN_PROCESS_SET);
+
+ panel.add(new ActionLink<BpmnProcessTO>() {
+
+ private static final long serialVersionUID = -7978723352517770644L;
+
+ @Override
+ protected boolean statusCondition(final BpmnProcessTO modelObject) {
+ return !modelObject.isUserWorkflow();
+ }
+
+ @Override
+ public void onClick(final AjaxRequestTarget target, final BpmnProcessTO ignore) {
+ try {
+ restClient.deleteDefinition(model.getObject().getKey());
+ SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+ target.add(container);
+ } catch (SyncopeClientException e) {
+ LOG.error("While deleting BPMN definition {}", model.getObject().getName(), e);
+ SyncopeConsoleSession.get().error(
+ StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
+ }
+ ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+ }
+ }, ActionLink.ActionType.DELETE, FlowableEntitlement.BPMN_PROCESS_DELETE, true);
+
+ return panel;
+ }
+
+ @Override
+ protected Collection<ActionLink.ActionType> getBatches() {
+ return Collections.emptyList();
+ }
+
+ public abstract static class Builder
+ extends DirectoryPanel.Builder<BpmnProcessTO, BpmnProcessTO, BpmnProcessRestClient> {
+
+ private static final long serialVersionUID = 5088962796986706805L;
+
+ public Builder(final PageReference pageRef) {
+ super(new BpmnProcessRestClient(), pageRef);
+ }
+
+ @Override
+ protected WizardMgtPanel<BpmnProcessTO> newInstance(final String id, final boolean wizardInModal) {
+ return new BpmnProcessDirectoryPanel(id, this);
+ }
+ }
+
+ protected class BpmProcessDataProvider extends DirectoryDataProvider<BpmnProcessTO> {
+
+ private static final long serialVersionUID = 1764153405387687592L;
+
+ private final SortableDataProviderComparator<BpmnProcessTO> comparator;
+
+ private final BpmnProcessRestClient restClient = new BpmnProcessRestClient();
+
+ public BpmProcessDataProvider(final int paginatorRows) {
+ super(paginatorRows);
+ this.comparator = new SortableDataProviderComparator<>(this);
+ setSort("key", SortOrder.ASCENDING);
+ }
+
+ @Override
+ public Iterator<BpmnProcessTO> iterator(final long first, final long count) {
+ List<BpmnProcessTO> result = restClient.getDefinitions();
+ Collections.sort(result, comparator);
+ return result.subList((int) first, (int) first + (int) count).iterator();
+ }
+
+ @Override
+ public long size() {
+ return restClient.getDefinitions().size();
+ }
+
+ @Override
+ public IModel<BpmnProcessTO> model(final BpmnProcessTO object) {
+ return new CompoundPropertyModel<>(object);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/NewBpmnProcess.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/NewBpmnProcess.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/NewBpmnProcess.java
new file mode 100644
index 0000000..e28fb62
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/NewBpmnProcess.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import javax.ws.rs.core.MediaType;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.pdfbox.util.Charsets;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.rest.BpmnProcessRestClient;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextField;
+import org.apache.wicket.model.Model;
+
+public class NewBpmnProcess extends TogglePanel<Serializable> {
+
+ private static final long serialVersionUID = -4886361549305302161L;
+
+ private final BpmnProcessRestClient restClient = new BpmnProcessRestClient();
+
+ private final Form<?> form;
+
+ public NewBpmnProcess(final String id, final WebMarkupContainer container, final PageReference pageRef) {
+ super(id, pageRef);
+
+ form = new Form<>("form");
+ addInnerObject(form);
+
+ final TextField<String> key = new TextField<>("key", new Model<>());
+ key.setRequired(true);
+ form.add(key);
+
+ form.add(new AjaxSubmitLink("submit", form) {
+
+ private static final long serialVersionUID = 4947613489823025052L;
+
+ @Override
+ protected void onSubmit(final AjaxRequestTarget target) {
+ try {
+ restClient.setDefinition(MediaType.APPLICATION_XML_TYPE, key.getModelObject(),
+ IOUtils.toString(
+ getClass().getResourceAsStream("empty.bpmn20.xml"),
+ Charsets.UTF_8.name()).replaceAll("%KEY%", key.getModelObject()));
+
+ key.getModel().setObject(null);
+ SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+ toggle(target, false);
+ target.add(container);
+ } catch (Exception e) {
+ LOG.error("While creating new BPMN process", e);
+ SyncopeConsoleSession.get().error(
+ StringUtils.isBlank(e.getMessage())
+ ? e.getClass().getName() : e.getMessage());
+ }
+ ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+ }
+
+ @Override
+ protected void onError(final AjaxRequestTarget target) {
+ ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+ }
+ });
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/AbstractBpmnProcessResource.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/AbstractBpmnProcessResource.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/AbstractBpmnProcessResource.java
new file mode 100644
index 0000000..91a42e3
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/AbstractBpmnProcessResource.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.resources;
+
+import javax.ws.rs.NotFoundException;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.BpmnProcessRestClient;
+import org.apache.syncope.common.lib.to.BpmnProcessTO;
+import org.apache.wicket.request.resource.AbstractResource;
+import org.apache.wicket.util.string.StringValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+abstract class AbstractBpmnProcessResource extends AbstractResource {
+
+ private static final long serialVersionUID = 5163553843196539019L;
+
+ protected static final Logger LOG = LoggerFactory.getLogger(AbstractBpmnProcessResource.class);
+
+ protected final BpmnProcessRestClient restClient = new BpmnProcessRestClient();
+
+ protected BpmnProcessTO getBpmnProcess(final Attributes attributes) {
+ StringValue modelId = attributes.getRequest().getQueryParameters().getParameterValue(Constants.MODEL_ID_PARAM);
+
+ BpmnProcessTO bpmnProcess = modelId == null || modelId.isNull()
+ ? null
+ : restClient.getDefinitions().stream().
+ filter(object -> modelId.toString().equals(object.getModelId())).findAny().orElse(null);
+ if (bpmnProcess == null) {
+ throw new NotFoundException("BPMN process with modelId " + modelId);
+ }
+
+ return bpmnProcess;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/BpmnProcessGETResource.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/BpmnProcessGETResource.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/BpmnProcessGETResource.java
new file mode 100644
index 0000000..ba34502
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/BpmnProcessGETResource.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.resources;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import javax.ws.rs.core.MediaType;
+import org.apache.syncope.client.console.annotations.Resource;
+import org.apache.syncope.client.console.rest.BpmnProcessRestClient;
+import org.apache.syncope.common.lib.to.BpmnProcessTO;
+import org.apache.wicket.util.io.IOUtils;
+
+/**
+ * Mirror REST resource for obtaining BPMN process in JSON (used by Flowable Modeler).
+ */
+@Resource(key = "bpmnProcessGET", path = "/bpmnProcessGET")
+public class BpmnProcessGETResource extends AbstractBpmnProcessResource {
+
+ private static final long serialVersionUID = 4637304868056148970L;
+
+ @Override
+ protected ResourceResponse newResourceResponse(final Attributes attributes) {
+ final BpmnProcessTO toGet = getBpmnProcess(attributes);
+
+ ResourceResponse response = new ResourceResponse();
+ response.disableCaching();
+ response.setContentType(MediaType.APPLICATION_JSON);
+ response.setTextEncoding(StandardCharsets.UTF_8.name());
+ response.setWriteCallback(new WriteCallback() {
+
+ @Override
+ public void writeData(final Attributes attributes) throws IOException {
+ IOUtils.copy(new BpmnProcessRestClient().getDefinition(MediaType.APPLICATION_JSON_TYPE, toGet.getKey()),
+ attributes.getResponse().getOutputStream());
+ }
+ });
+
+ return response;
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/BpmnProcessPUTResource.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/BpmnProcessPUTResource.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/BpmnProcessPUTResource.java
new file mode 100644
index 0000000..d583396
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/resources/BpmnProcessPUTResource.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.resources;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.common.util.UrlUtils;
+import org.apache.syncope.client.console.annotations.Resource;
+import org.apache.syncope.common.lib.to.BpmnProcessTO;
+import org.apache.wicket.util.io.IOUtils;
+
+/**
+ * Mirror REST resource for setting BPMN process in JSON (used by Flowable Modeler).
+ */
+@Resource(key = "bpmnProcessPUT", path = "/bpmnProcessPUT")
+public class BpmnProcessPUTResource extends AbstractBpmnProcessResource {
+
+ private static final long serialVersionUID = 2964542005207297944L;
+
+ @Override
+ protected ResourceResponse newResourceResponse(final Attributes attributes) {
+ String definition = null;
+ try {
+ HttpServletRequest request = (HttpServletRequest) attributes.getRequest().getContainerRequest();
+ String requestBody = IOUtils.toString(request.getInputStream());
+ String[] split = requestBody.split("&");
+ for (int i = 0; i < split.length && definition == null; i++) {
+ String keyValue = split[i];
+ if (keyValue.startsWith("json_xml=")) {
+ definition = UrlUtils.urlDecode(keyValue.split("=")[1]);
+ }
+ }
+ } catch (IOException e) {
+ LOG.error("Could not extract BPMN process", e);
+ }
+
+ BpmnProcessTO toSet = getBpmnProcess(attributes);
+
+ if (definition == null || toSet == null) {
+ return new ResourceResponse().setStatusCode(Response.Status.BAD_REQUEST.getStatusCode()).
+ setError(Response.Status.BAD_REQUEST.getStatusCode(),
+ "Could not extract BPMN process' model id and / or definition");
+ }
+
+ try {
+ restClient.setDefinition(MediaType.APPLICATION_JSON_TYPE, toSet.getKey(), definition);
+ return new ResourceResponse().setStatusCode(Response.Status.NO_CONTENT.getStatusCode());
+ } catch (Exception e) {
+ LOG.error("While updating BPMN process", e);
+ return new ResourceResponse().setStatusCode(Response.Status.BAD_REQUEST.getStatusCode()).
+ setError(Response.Status.BAD_REQUEST.getStatusCode(),
+ "While updating BPMN process: " + e.getMessage());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/BpmnProcessRestClient.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/BpmnProcessRestClient.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/BpmnProcessRestClient.java
new file mode 100644
index 0000000..2b7c368
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/BpmnProcessRestClient.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.rest;
+
+import java.io.InputStream;
+import java.util.List;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.common.lib.to.BpmnProcessTO;
+import org.apache.syncope.common.rest.api.RESTHeaders;
+import org.apache.syncope.common.rest.api.service.BpmnProcessService;
+
+public class BpmnProcessRestClient extends BaseRestClient {
+
+ private static final long serialVersionUID = 5049285686167071017L;
+
+ private BpmnProcessService getService(final MediaType mediaType) {
+ return SyncopeConsoleSession.get().getService(mediaType, BpmnProcessService.class);
+ }
+
+ public List<BpmnProcessTO> getDefinitions() {
+ return getService(BpmnProcessService.class).list();
+ }
+
+ public InputStream getDefinition(final MediaType mediaType, final String key) {
+ Response response = getService(mediaType).get(key);
+
+ return (InputStream) response.getEntity();
+ }
+
+ public byte[] getDiagram(final String key) {
+ BpmnProcessService service = getService(BpmnProcessService.class);
+ WebClient.client(service).accept(RESTHeaders.MEDIATYPE_IMAGE_PNG);
+ Response response = service.exportDiagram(key);
+
+ byte[] diagram;
+ try {
+ diagram = IOUtils.readBytesFromStream((InputStream) response.getEntity());
+ } catch (Exception e) {
+ LOG.error("Could not get workflow diagram", e);
+ diagram = new byte[0];
+ }
+ return diagram;
+ }
+
+ public void setDefinition(final MediaType mediaType, final String key, final String definition) {
+ getService(mediaType).set(key, definition);
+ }
+
+ public void deleteDefinition(final String key) {
+ getService(BpmnProcessService.class).delete(key);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/UserRequestRestClient.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/UserRequestRestClient.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/UserRequestRestClient.java
new file mode 100644
index 0000000..555555b
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/UserRequestRestClient.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.rest;
+
+import java.util.List;
+import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.rest.api.beans.UserRequestFormQuery;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.apache.syncope.common.rest.api.service.UserRequestService;
+
+public class UserRequestRestClient extends BaseRestClient {
+
+ private static final long serialVersionUID = -4785231164900813921L;
+
+ public int countForms() {
+ return getService(UserRequestService.class).
+ getForms(new UserRequestFormQuery.Builder().page(1).size(1).build()).
+ getTotalCount();
+ }
+
+ public List<UserRequestForm> getForms(final int page, final int size, final SortParam<String> sort) {
+ return getService(UserRequestService.class).
+ getForms(new UserRequestFormQuery.Builder().page(page).size(size).orderBy(toOrderBy(sort)).build()).
+ getResult();
+ }
+
+ public List<UserRequestForm> getForms(final String userKey) {
+ return getService(UserRequestService.class).getForms(userKey);
+ }
+
+ public UserRequestForm claimForm(final String taskKey) {
+ return getService(UserRequestService.class).claimForm(taskKey);
+ }
+
+ public void submitForm(final UserRequestForm form) {
+ getService(UserRequestService.class).submitForm(form);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowTaskRestClient.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowTaskRestClient.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowTaskRestClient.java
new file mode 100644
index 0000000..68d5856
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowTaskRestClient.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.rest;
+
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.to.WorkflowTaskExecInput;
+import org.apache.syncope.common.rest.api.service.UserWorkflowTaskService;
+
+public class UserWorkflowTaskRestClient extends BaseRestClient {
+
+ private static final long serialVersionUID = 5765024947677482995L;
+
+ public UserTO executeNextTask(final UserTO userTO) {
+ WorkflowTaskExecInput input = new WorkflowTaskExecInput();
+ input.setUserKey(userTO.getKey());
+ return getService(UserWorkflowTaskService.class).executeNextTask(input);
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
new file mode 100644
index 0000000..8f8329e
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.widgets;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.image.Icon;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconTypeBuilder;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.annotations.ExtWidget;
+import org.apache.syncope.client.console.pages.Approvals;
+import org.apache.syncope.client.console.rest.UserRequestRestClient;
+import org.apache.syncope.client.console.wicket.ajax.IndicatorAjaxTimerBehavior;
+import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.types.FlowableEntitlement;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
+import org.apache.wicket.markup.html.WebPage;
+import org.apache.wicket.markup.html.link.AbstractLink;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.util.ListModel;
+import org.apache.wicket.util.time.Duration;
+
+@ExtWidget(priority = 10)
+public class ApprovalsWidget extends ExtAlertWidget<UserRequestForm> {
+
+ private static final long serialVersionUID = 7667120094526529934L;
+
+ private final UserRequestRestClient restClient = new UserRequestRestClient();
+
+ private final List<UserRequestForm> lastApprovals = new ArrayList<>();
+
+ public ApprovalsWidget(final String id, final PageReference pageRef) {
+ super(id);
+ setOutputMarkupId(true);
+
+ latestAlertsList.add(new IndicatorAjaxTimerBehavior(Duration.seconds(30)) {
+
+ private static final long serialVersionUID = 7298597675929755960L;
+
+ @Override
+ protected void onTimer(final AjaxRequestTarget target) {
+ if (!latestAlerts.getObject().equals(lastApprovals)) {
+ refreshLatestAlerts(target);
+ }
+ }
+ });
+ }
+
+ public final void refreshLatestAlerts(final AjaxRequestTarget target) {
+ latestAlerts.getObject().clear();
+ latestAlerts.getObject().addAll(lastApprovals);
+
+ int latestAlertSize = getLatestAlertsSize();
+ linkAlertsNumber.setDefaultModelObject(latestAlertSize);
+ target.add(linkAlertsNumber);
+
+ headerAlertsNumber.setDefaultModelObject(latestAlertSize);
+ target.add(headerAlertsNumber);
+
+ target.add(latestAlertsList);
+
+ lastApprovals.clear();
+ lastApprovals.addAll(latestAlerts.getObject());
+ }
+
+ @Override
+ protected int getLatestAlertsSize() {
+ return SyncopeConsoleSession.get().owns(FlowableEntitlement.WORKFLOW_FORM_LIST)
+ && SyncopeConsoleSession.get().owns(FlowableEntitlement.WORKFLOW_FORM_READ)
+ ? restClient.countForms()
+ : 0;
+ }
+
+ @Override
+ protected IModel<List<UserRequestForm>> getLatestAlerts() {
+ return new ListModel<UserRequestForm>() {
+
+ private static final long serialVersionUID = -2583290457773357445L;
+
+ @Override
+ public List<UserRequestForm> getObject() {
+ List<UserRequestForm> updatedApprovals;
+ if (SyncopeConsoleSession.get().owns(FlowableEntitlement.WORKFLOW_FORM_LIST)
+ && SyncopeConsoleSession.get().owns(FlowableEntitlement.WORKFLOW_FORM_READ)) {
+
+ updatedApprovals = restClient.getForms(1, MAX_SIZE, new SortParam<>("createTime", true));
+ } else {
+ updatedApprovals = Collections.<UserRequestForm>emptyList();
+ }
+
+ return updatedApprovals;
+ }
+ };
+ }
+
+ @Override
+ protected AbstractLink getEventsLink(final String linkid) {
+ BookmarkablePageLink<Approvals> approvals = BookmarkablePageLinkBuilder.build(linkid, Approvals.class);
+ MetaDataRoleAuthorizationStrategy.authorize(approvals, WebPage.ENABLE, FlowableEntitlement.WORKFLOW_FORM_LIST);
+ return approvals;
+ }
+
+ @Override
+ protected Icon getIcon(final String iconid) {
+ return new Icon(iconid,
+ FontAwesomeIconTypeBuilder.on(FontAwesomeIconTypeBuilder.FontAwesomeGraphic.handshake_o).build());
+ }
+}
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/app-cfg.js
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/app-cfg.js b/ext/flowable/client-console/src/main/resources/app-cfg.js
new file mode 100644
index 0000000..15ec23a
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/app-cfg.js
@@ -0,0 +1,25 @@
+/* Copyright 2005-2015 Alfresco Software, Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+var FLOWABLE = FLOWABLE || {};
+
+FLOWABLE.CONFIG = {
+ 'onPremise' : true,
+ 'contextRoot': window.location.toString().substr(0, window.location.toString().indexOf('/flowable-modeler')) + '/flowable-modeler',
+ 'webContextRoot': window.location.toString().substr(0, window.location.toString().indexOf('/flowable-modeler') + '/flowable-modeler'),
+ 'datesLocalization' : false
+};
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval.html
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval.html b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval.html
new file mode 100644
index 0000000..64805b9
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval.html
@@ -0,0 +1,31 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+ <wicket:panel>
+ <div wicket:id="propView">
+ <span wicket:id="value">[value]</span>
+ </div>
+
+ <div style="margin: 20px 0">
+ <a href="#" alt="user details" class="btn btn-primary btn-circle btn-lg" wicket:id="userDetails" wicket:message="title:userDetails">
+ <i class="glyphicon glyphicon-eye-open"></i>
+ </a>
+ </div>
+ </wicket:panel>
+</html>
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval.properties
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval.properties b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval.properties
new file mode 100644
index 0000000..450ff50
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+userDetails=User details
+userForm=Edit User
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalDetails.html
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalDetails.html b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalDetails.html
new file mode 100644
index 0000000..1de2361
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalDetails.html
@@ -0,0 +1,23 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+ <wicket:panel>
+ <span wicket:id="wizard"/>
+ </wicket:panel>
+</html>
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal.html
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal.html b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal.html
new file mode 100644
index 0000000..5d5d129
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal.html
@@ -0,0 +1,23 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
+ <wicket:panel>
+ <span wicket:id="approval">[APPROVAL]</span>
+ </wicket:panel>
+</html>
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal.properties
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal.properties b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal.properties
new file mode 100644
index 0000000..941c896
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+approval.details=Approval details
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_it.properties
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_it.properties b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_it.properties
new file mode 100644
index 0000000..941c896
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_it.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+approval.details=Approval details
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_ja.properties
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_ja.properties b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_ja.properties
new file mode 100644
index 0000000..84106b9
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_ja.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+approval.details=\u627f\u8a8d\u8a73\u7d30
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_pt_BR.properties
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_pt_BR.properties b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_pt_BR.properties
new file mode 100644
index 0000000..941c896
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_pt_BR.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+approval.details=Approval details
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_ru.properties
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_ru.properties b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_ru.properties
new file mode 100644
index 0000000..941c896
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/ApprovalModal_ru.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+approval.details=Approval details
http://git-wip-us.apache.org/repos/asf/syncope/blob/66b3a04e/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval_it.properties
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval_it.properties b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval_it.properties
new file mode 100644
index 0000000..92c475d
--- /dev/null
+++ b/ext/flowable/client-console/src/main/resources/org/apache/syncope/client/console/approvals/Approval_it.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+userDetails=Dettagli utente
+userForm=Modifica utente