Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.jmix.flowui.action.DialogAction;
import io.jmix.flowui.component.genericfilter.Configuration;
import io.jmix.flowui.component.genericfilter.GenericFilterSupport;
import io.jmix.flowui.component.genericfilter.MutableConfiguration;
import io.jmix.flowui.component.genericfilter.configuration.DesignTimeConfiguration;
import io.jmix.flowui.component.genericfilter.model.FilterConfigurationModel;
import io.jmix.flowui.icon.Icons;
Expand Down Expand Up @@ -91,6 +92,8 @@ protected boolean isApplicable() {
return super.isApplicable()
&& target.getCurrentConfiguration() != target.getEmptyConfiguration()
&& !(target.getCurrentConfiguration() instanceof DesignTimeConfiguration)
&& !(target.getCurrentConfiguration() instanceof MutableConfiguration mc
&& mc.isProtectedFromUserDeletion())
&& (globalConfigurationModificationPermitted || !isCurrentConfigurationAvailableForAll());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,18 @@

import io.jmix.core.querycondition.LogicalCondition;
import io.jmix.flowui.component.filter.FilterComponent;
import io.jmix.flowui.component.genericfilter.configuration.DesignTimeConfiguration;
import io.jmix.flowui.component.genericfilter.configuration.RunTimeConfiguration;
import io.jmix.flowui.component.logicalfilter.LogicalFilterComponent;

import org.jspecify.annotations.Nullable;
import org.springframework.lang.Nullable;

/**
* A configuration is a set of filter components.
*
* <p><b>Note:</b> several mutating methods declared in this interface throw
* {@link UnsupportedOperationException} when called on a {@link DesignTimeConfiguration}.
* Those methods are deprecated — use {@link MutableConfiguration} when you need to call them.
*/
public interface Configuration extends Comparable<Configuration> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a lot of calls of all deprecated method. I think we should rewrite out own API if it is possible. Otherwise why do we introduce a new API if we are not using it.

Don't forget about backward compatibility.


Expand All @@ -45,12 +50,15 @@ public interface Configuration extends Comparable<Configuration> {
String getName();

/**
* Sets the name of configuration. This method is only available for
* the {@link RunTimeConfiguration}.
* Sets the name of configuration.
*
* @param name a configuration name
* @throws UnsupportedOperationException when called on {@link DesignTimeConfiguration}
* @deprecated use {@link MutableConfiguration} instead

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For use instead we should pass the appropriate methods in new interface e.g.:{@link MutableConfiguration#setName}

* @see MutableConfiguration
* @see RunTimeConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
void setName(@Nullable String name);

/**
Expand All @@ -60,13 +68,16 @@ public interface Configuration extends Comparable<Configuration> {
LogicalFilterComponent<?> getRootLogicalFilterComponent();

/**
* Sets the root element of configuration. This method is only available for
* the {@link RunTimeConfiguration}.
* Sets the root element of configuration.
*
* @param rootLogicalFilterComponent a root element of configuration
* @throws UnsupportedOperationException when called on {@link DesignTimeConfiguration}
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
* @see LogicalFilterComponent
* @see RunTimeConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
void setRootLogicalFilterComponent(LogicalFilterComponent<?> rootLogicalFilterComponent);

/**
Expand All @@ -76,15 +87,22 @@ public interface Configuration extends Comparable<Configuration> {

/**
* @return true if the configuration is modified
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
boolean isModified();

/**
* Sets whether configuration is modified. If a filter component is modified,
* then a remove button appears next to it.
*
* @param modified whether configuration is modified.
* @param modified whether configuration is modified
* @throws UnsupportedOperationException when called on {@link DesignTimeConfiguration}
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
void setModified(boolean modified);

/**
Expand All @@ -93,7 +111,10 @@ public interface Configuration extends Comparable<Configuration> {
*
* @param filterComponent the filter component to check
* @return whether the filter component of configuration is modified
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
boolean isFilterComponentModified(FilterComponent filterComponent);

/**
Expand All @@ -102,24 +123,40 @@ public interface Configuration extends Comparable<Configuration> {
*
* @param filterComponent a filter component
* @param modified whether the filter component of configuration is modified
* @throws UnsupportedOperationException when called on {@link DesignTimeConfiguration}
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
void setFilterComponentModified(FilterComponent filterComponent, boolean modified);

/**
* Sets a default value of {@link FilterComponent} for the configuration by the parameter name.
* This allows the default values to be saved and displayed in the configuration editor.
*
* <p>On {@link io.jmix.flowui.component.genericfilter.configuration.DesignTimeConfiguration}
* this method is intended for framework-internal initialization only (e.g. XML loader).
* For {@link io.jmix.flowui.component.genericfilter.configuration.RunTimeConfiguration},
* use {@link MutableConfiguration#setFilterComponentDefaultValue} instead.
*
* @param parameterName a parameter name of filter component
* @param defaultValue a default value
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
void setFilterComponentDefaultValue(String parameterName, @Nullable Object defaultValue);

/**
* Resets a default value of {@link FilterComponent}. The default value for the filter
* component becomes null.
*
* @param parameterName a parameter name of filter component
* @throws UnsupportedOperationException when called on {@link DesignTimeConfiguration}
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
void resetFilterComponentDefaultValue(String parameterName);

/**
Expand All @@ -133,20 +170,33 @@ public interface Configuration extends Comparable<Configuration> {

/**
* Sets null as the default value for all configuration filter components.
*
* @throws UnsupportedOperationException when called on {@link DesignTimeConfiguration}
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
void resetAllDefaultValues();

/**
* Returns whether the configuration is available for all users
* Returns whether the configuration is available for all users.
*
* @return true if the configuration is available for all users, otherwise false.
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
default boolean isAvailableForAllUsers() {
return false;
}
Comment on lines +188 to 191

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method shouldn't be deprecated because it used for calculating configuration name for all types of configuration


/**
* Sets whether the configuration is available for all users or not
*
* @deprecated use {@link MutableConfiguration} instead
* @see MutableConfiguration
*/
@Deprecated(since = "3.0", forRemoval = true)
default void setAvailableForAllUsers(boolean availableForAllUsers) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,35 @@ public void setCurrentConfiguration(Configuration currentConfiguration) {
setCurrentConfigurationInternal(currentConfiguration, false);
}

/**
* Registers the given configuration with this filter and immediately sets it as the current
* configuration, in the correct order and in a single call.
* <p>
* This is a convenience alternative to calling {@link #addConfiguration(Configuration)}
* followed by {@link #setCurrentConfiguration(Configuration)}, which fails silently when
* the configuration is not yet registered at the time {@code setCurrentConfiguration} is
* invoked.
*
* @param configuration the configuration to register and activate
*/
public void addAndSetCurrentConfiguration(Configuration configuration) {
addConfiguration(configuration);
setCurrentConfiguration(configuration);
}
Comment on lines +617 to +620

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a useless method. I think we should throw an exception or write a error log message when the user or programmer trying to set current configuration which does not exist.


/**
* Refreshes the layout of the current configuration.
* <p>
* Call this method after programmatically modifying the current configuration's filter
* components (e.g. adding a component to the root {@link LogicalFilterComponent}) to force
* the filter UI to re-render remove buttons and update the data-loader condition.
* <p>
* This is a stable public equivalent of the internal {@code refreshCurrentConfigurationLayout()}.
*/
public void refreshCurrentConfiguration() {
refreshCurrentConfigurationLayout();
}

protected void setCurrentConfigurationInternal(Configuration currentConfiguration, boolean fromClient) {
if (configurations.contains(currentConfiguration)
|| getEmptyConfiguration().equals(currentConfiguration)) {
Expand Down Expand Up @@ -891,7 +920,8 @@ public void addConfiguration(Configuration configuration) {
*/
public void removeConfiguration(Configuration configuration) {
if (configuration != getEmptyConfiguration()
&& !(configuration instanceof DesignTimeConfiguration)) {
&& !(configuration instanceof DesignTimeConfiguration)
&& !(configuration instanceof MutableConfiguration mc && mc.isProtectedFromUserDeletion())) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't re-check this condition here. The runtime configuration should be available for internal removing, e.g. for the renaming process in the io.jmix.flowui.component.genericfilter.GenericFilterSupport#initFilterConfiguration. Otherwise the configuration will be duplicated.

Availablility of user-deletion should be handled (and already handled) in the GenericFilterRemoveAction isApplicable method.

configurations.remove(configuration);
configuration.getRootLogicalFilterComponent().getElement().removeFromParent();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright 2024 Haulmont.
*
* 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.
*/

package io.jmix.flowui.component.genericfilter;

import io.jmix.flowui.component.filter.FilterComponent;
import io.jmix.flowui.component.genericfilter.configuration.DesignTimeConfiguration;
import io.jmix.flowui.component.genericfilter.configuration.RunTimeConfiguration;
import io.jmix.flowui.component.logicalfilter.LogicalFilterComponent;
import org.springframework.lang.Nullable;

/**
* A mutable extension of {@link Configuration}.
* <p>
* {@link RunTimeConfiguration} implements this interface. {@link DesignTimeConfiguration}
* only implements the read-only {@link Configuration}.
* <p>
* Use this interface as the declared type when you need to call mutating methods,
* so the compiler catches misuse of {@link DesignTimeConfiguration} at compile time:
* <pre>{@code
* MutableConfiguration config = filter.runtimeConfigurationBuilder()
* .id("myConfig")
* .buildAndRegister();
* config.setModified(true);
* }</pre>
Comment on lines +27 to +38

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a useless information, especially about implementations. Moreover, there is no runtimeConfigurationBuilder and such API on this moment.

*
* @see Configuration
* @see RunTimeConfiguration
*/
@SuppressWarnings({"deprecation", "removal"})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we shouldn't suppress this warnings on whole class

public interface MutableConfiguration extends Configuration {

/**
* Returns whether the configuration is modified.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@returns should be used, the same for all classes

* If a filter component is modified, a remove button appears next to it.
*/
boolean isModified();

/**
* Returns whether the given filter component is modified.
* If a filter component is modified, a remove button appears next to it.
*
* @param filterComponent the filter component to check
*/
boolean isFilterComponentModified(FilterComponent filterComponent);

/**
* Sets the name of configuration.
*
* @param name a configuration name
*/
void setName(@Nullable String name);

/**
* Sets the root logical filter component of configuration.
*
* @param rootLogicalFilterComponent a root element of configuration
*/
void setRootLogicalFilterComponent(LogicalFilterComponent<?> rootLogicalFilterComponent);

/**
* Sets whether the configuration is modified.
* If a filter component is modified, a remove button appears next to it.
* <p>
* Note: this method iterates over components already added to the root at the time of the call.
*
* @param modified whether configuration is modified
*/
void setModified(boolean modified);

/**
* Sets whether the given filter component of configuration is modified.
* If a filter component is modified, a remove button appears next to it.
*
* @param filterComponent a filter component
* @param modified whether the filter component of configuration is modified
*/
void setFilterComponentModified(FilterComponent filterComponent, boolean modified);

/**
* Sets a default value of the given filter component for the configuration.
* This allows the default values to be saved and displayed in the configuration editor.
*
* @param parameterName a parameter name of filter component
* @param defaultValue a default value
*/
void setFilterComponentDefaultValue(String parameterName, @Nullable Object defaultValue);

/**
* Resets the default value of the filter component identified by the parameter name.
*
* @param parameterName a parameter name of filter component
*/
void resetFilterComponentDefaultValue(String parameterName);

/**
* Sets null as the default value for all configuration filter components.
*/
void resetAllDefaultValues();

/**
* Returns whether the configuration is available for all users.
*/
boolean isAvailableForAllUsers();

/**
* Sets whether the configuration is available for all users.
*
* @param availableForAllUsers whether the configuration is available for all users
*/
void setAvailableForAllUsers(boolean availableForAllUsers);

/**
* Returns whether this configuration is protected from deletion by the user through the UI.
* <p>
* When {@code true}, the Remove action in the filter toolbar is hidden for this configuration,
* and {@link GenericFilter#removeConfiguration} will not remove it even if called directly.
*/
boolean isProtectedFromUserDeletion();

/**
* Sets whether this configuration is protected from deletion by the user through the UI.
*
* @param value {@code true} to prevent the user from deleting this configuration
*/
void setProtectedFromUserDeletion(boolean value);

}
Loading