Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Add util method for detecting Hilla auto layout #20245

Merged
merged 7 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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 @@ -31,8 +31,10 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -44,6 +46,7 @@
import org.slf4j.LoggerFactory;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.function.SerializableConsumer;
import com.vaadin.flow.router.BeforeEnterListener;
import com.vaadin.flow.router.MenuData;
import com.vaadin.flow.router.PageTitle;
Expand Down Expand Up @@ -303,39 +306,77 @@ public static Map<String, AvailableViewInfo> collectClientMenuItems(
boolean filterClientViews, AbstractConfiguration configuration,
VaadinRequest vaadinRequest) {

Map<String, AvailableViewInfo> configurations = new HashMap<>();

collectClientMenuItems(configuration,
clientViewConfig -> collectClientViews("", clientViewConfig,
configurations));

if (filterClientViews && !configurations.isEmpty()) {
filterClientViews(configurations, vaadinRequest);
}

return configurations;
}

/**
* Determines whether the application contains a Hilla auto layout.
* <p>
* This method checks if any of the client view configurations in the
* {@code file-routes.json} file correspond to a main menu layout, i.e. has
* children views.
*
* @param configuration
* the {@link AbstractConfiguration} containing the application
* configuration
* @return {@code true} if a Hilla auto layout is present in the
* configuration, {@code false} otherwise
*/
public static boolean hasHillaAutoLayout(
AbstractConfiguration configuration) {
AtomicBoolean hasHillaAutoLayout = new AtomicBoolean(false);
collectClientMenuItems(configuration, clientViewConfig -> {
if (!hasHillaAutoLayout.get() && isMainLayout(clientViewConfig)) {
hasHillaAutoLayout.compareAndSet(false, true);
}
});
return hasHillaAutoLayout.get();
}

private static boolean isMainLayout(AvailableViewInfo viewInfo) {
return (viewInfo.route() == null || viewInfo.route().isBlank())
&& viewInfo.children() != null;
caalador marked this conversation as resolved.
Show resolved Hide resolved
}

private static void collectClientMenuItems(
AbstractConfiguration configuration,
SerializableConsumer<AvailableViewInfo> viewInfoConsumer) {
Objects.requireNonNull(configuration);
Objects.requireNonNull(viewInfoConsumer);
URL viewsJsonAsResource = getViewsJsonAsResource(configuration);
if (viewsJsonAsResource == null) {
LoggerFactory.getLogger(MenuRegistry.class).debug(
"No {} found under {} directory. Skipping client route registration.",
FILE_ROUTES_JSON_NAME,
configuration.isProductionMode() ? "'META-INF/VAADIN'"
: "'frontend/generated'");
return Collections.emptyMap();
return;
}

Map<String, AvailableViewInfo> configurations = new HashMap<>();

try (InputStream source = viewsJsonAsResource.openStream()) {
if (source != null) {
ObjectMapper mapper = new ObjectMapper().configure(
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
mapper.readValue(source,
new TypeReference<List<AvailableViewInfo>>() {
}).forEach(clientViewConfig -> collectClientViews("",
clientViewConfig, configurations));
}).forEach(viewInfoConsumer);
}
} catch (IOException e) {
LoggerFactory.getLogger(MenuRegistry.class).warn(
"Failed load {} from {}", FILE_ROUTES_JSON_NAME,
viewsJsonAsResource.getPath(), e);
}

if (filterClientViews) {
filterClientViews(configurations, vaadinRequest);
}

return configurations;
}

private static void collectClientViews(String basePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@
import com.vaadin.flow.server.VaadinSession;
import com.vaadin.flow.server.startup.ApplicationRouteRegistry;

import elemental.json.JsonArray;
import elemental.json.JsonObject;
import elemental.json.impl.JsonUtil;
import static com.vaadin.flow.server.frontend.FrontendUtils.GENERATED;
import static com.vaadin.flow.internal.menu.MenuRegistry.FILE_ROUTES_JSON_NAME;
import static com.vaadin.flow.internal.menu.MenuRegistry.FILE_ROUTES_JSON_PROD_PATH;
Expand Down Expand Up @@ -331,6 +334,38 @@ public void getMenuItemsList_assertOrder() {
new String[] { "/d", "/c", "/a", "/b", "/d/a", "/d/b" });
}

@Test
public void hasHillaAutoLayout_fileRoutesHasLayout_true()
throws IOException {
JsonArray fileRoutes = JsonUtil.parse(testClientRouteFile);
JsonObject layout = fileRoutes.getObject(0);
JsonArray children = layout.getArray("children");
Assert.assertNotNull(children);
Assert.assertTrue(children.length() > 0);
caalador marked this conversation as resolved.
Show resolved Hide resolved

File generated = tmpDir.newFolder(GENERATED);
File clientFiles = new File(generated, FILE_ROUTES_JSON_NAME);
Files.writeString(clientFiles.toPath(), testClientRouteFile);

boolean hasHillaAutoLayout = MenuRegistry
.hasHillaAutoLayout(vaadinService.getDeploymentConfiguration());
Assert.assertTrue(hasHillaAutoLayout);
}

@Test
public void hasHillaAutoLayout_fileRoutesHasNoLayout_false()
throws IOException {
Assert.assertFalse(noLayoutsRouteFile.contains("\"children\""));

File generated = tmpDir.newFolder(GENERATED);
File clientFiles = new File(generated, FILE_ROUTES_JSON_NAME);
Files.writeString(clientFiles.toPath(), noLayoutsRouteFile);

boolean hasHillaAutoLayout = MenuRegistry
.hasHillaAutoLayout(vaadinService.getDeploymentConfiguration());
Assert.assertFalse(hasHillaAutoLayout);
}

private void assertOrder(List<AvailableViewInfo> menuItems,
String[] expectedOrder) {
for (int i = 0; i < menuItems.size(); i++) {
Expand Down Expand Up @@ -683,4 +718,19 @@ public Instantiator getInstantiator() {
}
]
""";

String noLayoutsRouteFile = """
[
{
"route": "",
"menu": {
"title": "Public page",
"icon": "vaadin:group"
},
"flowLayout": false,
"params": {},
"title": "Public"
}
]
""";
}