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

feat: generate layout.json #19933

Merged
merged 2 commits into from
Sep 13, 2024
Merged
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 @@ -20,6 +20,7 @@
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
Expand All @@ -28,10 +29,14 @@
import org.slf4j.LoggerFactory;

import com.vaadin.flow.internal.StringUtil;
import com.vaadin.flow.router.Layout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.ExecutionFailedException;
import com.vaadin.flow.server.Version;

import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonObject;
import static com.vaadin.flow.server.frontend.FileIOUtils.compareIgnoringIndentationEOLAndWhiteSpace;
import static java.nio.charset.StandardCharsets.UTF_8;

Expand Down Expand Up @@ -102,6 +107,7 @@ function build() {
private static final String VAADIN_REACT_TSX = "vaadin-react.tsx";
private static final String REACT_ADAPTER_TEMPLATE = "ReactAdapter.template";
private static final String REACT_ADAPTER_TSX = "ReactAdapter.tsx";
private static final String LAYOUTS_JSON = "layouts.json";
static final String FLOW_FLOW_TSX = "flow/" + FLOW_TSX;
static final String FLOW_REACT_ADAPTER_TSX = "flow/" + REACT_ADAPTER_TSX;
private static final String ROUTES_JS_IMPORT_PATH_TOKEN = "%routesJsImportPath%";
Expand Down Expand Up @@ -158,6 +164,8 @@ private void doExecute() throws ExecutionFailedException {
writeFile(flowTsx, getFileContent(FLOW_TSX));
writeFile(vaadinReactTsx,
getVaadinReactTsContent(routesTsx.exists()));
writeFile(new File(frontendGeneratedFolder, LAYOUTS_JSON),
layoutsContent());
if (fileAvailable(REACT_ADAPTER_TEMPLATE)) {
String reactAdapterContent = getFileContent(
REACT_ADAPTER_TEMPLATE);
Expand Down Expand Up @@ -193,6 +201,19 @@ && serverRoutesAvailable()) {
}
}

private String layoutsContent() {
JsonArray availableLayouts = Json.createArray();
Set<Class<?>> layoutClasses = options.getClassFinder()
.getAnnotatedClasses(Layout.class);
for (Class<?> layout : layoutClasses) {
JsonObject layoutObject = Json.createObject();
layoutObject.put("path",
layout.getAnnotation(Layout.class).value());
availableLayouts.set(availableLayouts.length(), layoutObject);
}
return availableLayouts.toJson();
}

private void cleanup() throws ExecutionFailedException {
try {
File frontendDirectory = options.getFrontendDirectory();
Expand All @@ -204,7 +225,9 @@ private void cleanup() throws ExecutionFailedException {
FLOW_REACT_ADAPTER_TSX);
File frontendGeneratedFolderRoutesTsx = new File(
frontendGeneratedFolder, FrontendUtils.ROUTES_TSX);
File layoutsJson = new File(frontendGeneratedFolder, LAYOUTS_JSON);
FileUtils.deleteQuietly(flowTsx);
FileUtils.deleteQuietly(layoutsJson);
FileUtils.deleteQuietly(vaadinReactTsx);
FileUtils.deleteQuietly(reactAdapterTsx);
FileUtils.deleteQuietly(frontendGeneratedFolderRoutesTsx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.router.Layout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.RouterLayout;
import com.vaadin.flow.server.ExecutionFailedException;
import com.vaadin.flow.server.frontend.scanner.ClassFinder;
import com.vaadin.tests.util.MockOptions;
Expand Down Expand Up @@ -82,6 +84,27 @@ public void reactFilesAreWrittenToFrontend()
"routes.tsx").exists());
Assert.assertFalse("Missing ./frontend/routes.tsx",
new File(frontend, "routes.tsx").exists());
Assert.assertTrue(
"Missing ./frontend/" + FrontendUtils.GENERATED
+ "layouts.json",
new File(new File(frontend, FrontendUtils.GENERATED),
"layouts.json").exists());
}

@Test
public void layoutsJson_containsExpectedPaths()
throws ExecutionFailedException, IOException {
Mockito.when(options.getClassFinder().getAnnotatedClasses(Layout.class))
.thenReturn(Collections.singleton(TestLayout.class));

TaskGenerateReactFiles task = new TaskGenerateReactFiles(options);
task.execute();

String layoutsContent = FileUtils.readFileToString(
new File(options.getFrontendGeneratedFolder(), "layouts.json"));

Assert.assertEquals("[{\"path\":\"/test\"}]", layoutsContent);

}

@Test
Expand Down Expand Up @@ -555,4 +578,9 @@ public void routesContainExport_oneSingleExport_exceptionThrown()
@Route("test")
private class TestRoute extends Component {
}

@Tag("div")
@Layout("/test")
private class TestLayout extends Component implements RouterLayout {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.vaadin.flow.internal.DevModeHandlerManager;
import com.vaadin.flow.internal.Template;
import com.vaadin.flow.router.HasErrorParameter;
import com.vaadin.flow.router.Layout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.LoadDependenciesOnStartup;
import com.vaadin.flow.server.PWA;
Expand Down Expand Up @@ -68,7 +69,7 @@
JavaScript.Container.class, Theme.class, NoTheme.class,
HasErrorParameter.class, PWA.class, AppShellConfigurator.class,
Template.class, LoadDependenciesOnStartup.class,
TypeScriptBootstrapModifier.class, Component.class })
TypeScriptBootstrapModifier.class, Component.class, Layout.class })
@WebListener
public class DevModeStartupListener
implements VaadinServletContextStartupInitializer, Serializable,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.internal.Template;
import com.vaadin.flow.router.HasErrorParameter;
import com.vaadin.flow.router.Layout;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.LoadDependenciesOnStartup;
import com.vaadin.flow.server.PWA;
Expand Down Expand Up @@ -69,7 +70,8 @@ public void applicableClasses_knownClasses() {
CssImport.Container.class, Theme.class, NoTheme.class,
HasErrorParameter.class, PWA.class, AppShellConfigurator.class,
Template.class, LoadDependenciesOnStartup.class,
Component.class, TypeScriptBootstrapModifier.class);
Component.class, TypeScriptBootstrapModifier.class,
Layout.class);

for (Class<?> clz : classes) {
assertTrue("should be a known class " + clz.getName(),
Expand Down
Loading