All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.imunity.console.tprofile.TranslationProfileEditor Maven / Gradle / Ivy

/*
 * Copyright (c) 2021 Bixbit - Krzysztof Benedyczak. All rights reserved.
 * See LICENCE.txt file for licensing information.
 */

package io.imunity.console.tprofile;


import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Unit;
import com.vaadin.flow.component.dnd.DropEffect;
import com.vaadin.flow.component.dnd.DropTarget;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.html.NativeLabel;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.data.binder.Binder;
import com.vaadin.flow.data.binder.ValidationResult;
import io.imunity.vaadin.elements.CssClassNames;
import io.imunity.vaadin.elements.LinkButton;
import io.imunity.vaadin.elements.NotificationPresenter;
import io.imunity.vaadin.endpoint.common.WebSession;
import io.imunity.vaadin.endpoint.common.api.HtmlTooltipFactory;
import pl.edu.icm.unity.base.exceptions.EngineException;
import pl.edu.icm.unity.base.message.MessageSource;
import pl.edu.icm.unity.base.translation.ProfileType;
import pl.edu.icm.unity.base.translation.TranslationProfile;
import pl.edu.icm.unity.base.translation.TranslationRule;
import pl.edu.icm.unity.engine.api.authn.remote.RemotelyAuthenticatedInput;
import pl.edu.icm.unity.engine.api.translation.TranslationActionFactory;
import pl.edu.icm.unity.engine.api.utils.TypesRegistryBase;
import io.imunity.vaadin.endpoint.common.exceptions.FormValidationException;
import io.imunity.vaadin.endpoint.common.bus.Event;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static io.imunity.vaadin.elements.CSSVars.*;
import static io.imunity.vaadin.elements.CssClassNames.DROP_LAYOUT;
import static io.imunity.vaadin.elements.CssClassNames.POINTER;

public class TranslationProfileEditor extends VerticalLayout
{
	protected MessageSource msg;
	protected NotificationPresenter notificationPresenter;
	protected ProfileType type;
	protected TypesRegistryBase> registry;
	protected TextField name;
	protected TextField description;
	private HorizontalLayout rulesHeader;
	protected VerticalLayout rulesLayout;
	protected List rules;
	private Icon addRule;

	private RemotelyAuthenticatedInput remoteAuthnInput;
	private StartStopButton testProfileButton;
	private final ActionParameterComponentProvider actionComponentProvider;
	private Binder binder;
	private boolean readOnlyMode;
	private EditorContext editorContext = EditorContext.EDITOR;
	private final HtmlTooltipFactory htmlTooltipFactory;
	private final Set usedNames;

	public TranslationProfileEditor(MessageSource msg,
			TypesRegistryBase> registry, ProfileType type,
			ActionParameterComponentProvider actionComponentProvider, NotificationPresenter notificationPresenter,
			HtmlTooltipFactory htmlTooltipFactory, Set usedNames)
	{
		this.msg = msg;
		this.registry = registry;
		this.type = type;
		this.actionComponentProvider = actionComponentProvider;
		this.rules = new ArrayList<>();
		this.notificationPresenter = notificationPresenter;
		this.htmlTooltipFactory = htmlTooltipFactory;
		this.usedNames = usedNames;
		initUI();
	}

	public void setValue(TranslationProfile toEdit)
	{
		binder.setBean(toEdit);
		name.setReadOnly(true);
		rules.clear();
		for (TranslationRule trule : toEdit.getRules())
			addRuleComponentAt(trule, rules.size());
		refreshRules();
	}

	public TranslationProfile getProfile() throws FormValidationException
	{
		int nvalidr = 0;
		for (RuleComponent cr : rules)
		{
			if (!cr.validateRule())
				nvalidr++;
		}

		if (!binder.isValid() || nvalidr != 0)
		{
			binder.validate();
			throw new FormValidationException();
		}

		List trules = new ArrayList<>();
		for (RuleComponent cr : rules)
		{
			TranslationRule r = cr.getRule();
			if (r != null)
				trules.add(r);
		}
		return new TranslationProfile(name.getValue(), description.getValue(),
				type, trules);
	}

	protected void initUI()
	{
		rulesLayout = new VerticalLayout();
		rulesLayout.setSpacing(false);
		rulesLayout.setMargin(false);
		rulesLayout.setSizeUndefined();
		rulesLayout.setWidthFull();
		rulesLayout.setPadding(false);


		name = new TextField();
		name.setWidth(TEXT_FIELD_MEDIUM.value());

		description = new TextField();
		description.setWidth(TEXT_FIELD_BIG.value());

		rulesHeader = new HorizontalLayout();
		rulesHeader.addClassName(CssClassNames.MARGIN_VERTICAL.getName());
		addRule = VaadinIcon.PLUS_CIRCLE_O.create();
		addRule.setTooltipText(msg.getMessage("TranslationProfileEditor.newRule"));
		addRule.addClickListener(event -> addRuleComponent(null));
		addRule.addClassName(POINTER.getName());

		testProfileButton = new StartStopButton();
		testProfileButton.setVisible(false);
		testProfileButton.setTooltipText(msg.getMessage("TranslationProfileEditor.testProfile"));
		testProfileButton.addClickListener(e -> testRules(), e -> clearTestResults());

		rulesHeader.add(new NativeLabel(msg.getMessage("TranslationProfileEditor.rules")), addRule, testProfileButton);
		rulesHeader.getStyle().set("margin-bottom", BIG_MARGIN.value());
		rulesHeader.setAlignItems(Alignment.CENTER);

		FormLayout main = new FormLayout();
		main.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1));
		main.addFormItem(name, msg.getMessage("TranslationProfileEditor.name"));
		main.addFormItem(description, msg.getMessage("ServiceEditorBase.description"));
		main.setSizeFull();

		VerticalLayout wrapper = new VerticalLayout();
		wrapper.setMargin(false);
		wrapper.setPadding(false);
		wrapper.setSpacing(false);
		Span span = new Span();
		span.setHeight(2, Unit.EM);
		wrapper.add(main, span, rulesHeader, rulesLayout);

		binder = new Binder<>(TranslationProfile.class);
		binder.forField(name)
				.asRequired(msg.getMessage("fieldRequired"))
				.withValidator((v, c) ->
				{
					if (!name.isReadOnly() && usedNames.contains(v))
						return ValidationResult.error(msg.getMessage("TranslationProfileEditor.nameError", v));
					return ValidationResult.ok();

				})
				.bind("name");
		binder.bind(description, "description");
		binder.setBean(new TranslationProfile(
				getDefaultName(usedNames), null, type,
				new ArrayList<>()));
		setSpacing(false);
		setMargin(false);
		setPadding(false);
		add(wrapper);
		refreshRules();
	}

	private String getDefaultName(Set usedNames)
	{
		String proposal = msg.getMessage("TranslationProfileEditor.defaultName");
		int i = 1;
		while (usedNames.contains(proposal))
		{
			proposal = msg.getMessage("TranslationProfileEditor.defaultName") + " " + i++;
		}

		return proposal;

	}

	protected void testRules()
	{
		for (RuleComponent rule : rules)
			rule.test(remoteAuthnInput);
	}

	protected void clearTestResults()
	{
		for (RuleComponent rule : rules)
			rule.clearTestResult();
	}

	private void addRuleComponent(TranslationRule trule)
	{
		RuleComponent r = addRuleComponentAt(trule, rules.size());
		if (trule == null)
			r.setFocus();
		r.setEditorContext(editorContext);

		refreshRules();
	}

	private RuleComponent addRuleComponentAt(TranslationRule trule, int index)
	{
		RuleComponent r = new RuleComponent(msg, registry,
				trule, actionComponentProvider, type, new CallbackImplementation(), notificationPresenter, htmlTooltipFactory);
		r.setEditorContext(editorContext);
		rules.add(index, r);
		return r;
	}

	protected void refreshRules()
	{
		rulesLayout.removeAll();
		if (rules.size() == 0)
			return;
		rulesLayout.add(getDropElement(0));
		for (RuleComponent r : rules)
		{
			if (rules.size() > 1)
			{
				r.setTopVisible(true);
				r.setBottomVisible(true);
			} else
			{
				r.setTopVisible(false);
				r.setBottomVisible(false);
			}
		}

		rules.get(0).setTopVisible(false);
		rules.get(rules.size() - 1).setBottomVisible(false);
		for (RuleComponent r : rules)
		{
			rulesLayout.add(r);
			rulesLayout.add(getDropElement(rules.indexOf(r)));
		}
	}

	public void refresh()
	{
		rules.forEach(RuleComponent::refresh);
	}

	private HorizontalLayout getDropElement(int pos)
	{
		HorizontalLayout drop = new HorizontalLayout();
		drop.setWidthFull();
		drop.setHeight(1, Unit.EM);
		drop.addClassName(DROP_LAYOUT.getName());

		DropTarget dropTarget = DropTarget.create(drop);
		dropTarget.setDropEffect(DropEffect.MOVE);
		dropTarget.addDropListener(event ->
		{
			Optional dragSource = event.getDragSourceComponent();
			if (dragSource.isPresent() && dragSource.get() instanceof LinkButton)
			{
				event.getDragData().ifPresent(data ->
				{
					RuleComponent sourceRule = (RuleComponent) data;
					rules.remove(sourceRule);
					rules.add(pos, sourceRule);
					refreshRules();
				});
			}
		});

		WebSession.getCurrent()
				.getEventBus()
				.addListener(e -> drop.setVisible(true), DragStartEvent.class);
		WebSession.getCurrent()
				.getEventBus()
				.addListener(e -> drop.setVisible(false), DragEndEvent.class);
		drop.setVisible(false);
		return drop;
	}

	public void setRemoteAuthnInput(RemotelyAuthenticatedInput remoteAuthnInput)
	{
		this.remoteAuthnInput = remoteAuthnInput;
		this.testProfileButton.setVisible(true);
	}

	public void setCopyMode()
	{
		name.setReadOnly(false);
		String old = name.getValue();
		name.setValue(msg.getMessage("TranslationProfileEditor.nameCopy", old));
	}

	public void setReadOnlyMode()
	{
		name.setReadOnly(true);
		description.setReadOnly(true);
		addRule.setVisible(false);
		for (RuleComponent rule : rules)
		{
			rule.setReadOnlyMode(true);
		}
		readOnlyMode = true;
	}

	public boolean isReadOnlyMode()
	{
		return readOnlyMode;
	}

	public void rulesOnlyMode()
	{
		removeAll();
		add(rulesHeader, rulesLayout);
	}

	public void focusFirst()
	{
	}

	public void setContext(EditorContext context)
	{
		if (context.equals(EditorContext.WIZARD))
		{
			description.setWidth(100, Unit.PERCENTAGE);
		}
		for (RuleComponent rule : rules)
		{
			rule.setEditorContext(context);
		}
		editorContext = context;

	}

	private final class CallbackImplementation implements RuleComponent.Callback
	{
		@Override
		public boolean remove(RuleComponent rule)
		{
			rules.remove(rule);
			refreshRules();
			return true;
		}

		@Override
		public boolean moveTop(RuleComponent rule)
		{
			rules.remove(rule);
			rules.add(0, rule);
			refreshRules();
			return true;
		}

		@Override
		public boolean moveBottom(RuleComponent rule)
		{
			rules.remove(rule);
			rules.add(rule);
			refreshRules();
			return true;
		}

		@Override
		public boolean embedProfile(RuleComponent rule, String profileName, ProfileType profileType)
		{
			int indexOf = rules.indexOf(rule);

			TranslationProfile profile;
			try
			{
				profile = (profileType == ProfileType.INPUT) ?
						actionComponentProvider.getInputProfile(profileName) :
						actionComponentProvider.getOutputProfile(profileName);
			} catch (EngineException e)
			{
				notificationPresenter.showError(msg.getMessage("TranslationProfilesComponent.errorReadData"), e.getMessage());
				return false;
			}

			for (TranslationRule trule : profile.getRules())
				addRuleComponentAt(trule, indexOf++);
			rules.remove(rule);
			refreshRules();
			return true;
		}
	}
	
	public static final class DragStartEvent implements Event
	{
		
	}
	
	public static final class DragEndEvent implements Event
	{
		
	}
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy