[#menu-bars-layout]
= Menu Bars Layout

:Notice: 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.


The actions of xref:domain-entities-and-services.adoc#domain-services[domain services] (annotated using xref:refguide:applib:index/annotation/DomainService.adoc[@DomainService] with a xref:refguide:applib:index/annotation/DomainService.adoc#nature[nature] of `VIEW`) are made available as menu items on menus.

For example:

[source,java]
----
@DomainService(
        nature = NatureOfService.VIEW,                              // <.>
        objectType = "simple.SimpleObjects"
        )
public class SimpleObjects {
    // ...
}
----
<.> Domain service with actions visible in the UI

By default each domain service corresponds to a single menu on this menu bar, with its actions as the drop-down menu items.

By annotating the domain service class and its actions, it's possible to have a little more control over the placement of the menu items; this is discussed xref:#annotation-based-menus[below].

For more fine-grained control, though, the `menubars.layout.xml` file can be supplied, as discussed xref:#file-based-menus[after].
This file is also read dynamically at runtime, so layouts can be changed during prototyping and the page reloaded to check.



[[annotation-based-menus]]
== Annotation-based

If using annotations, services can be added to either the primary, secondary or tertiary menu bar, as shown in this screenshot shows:

image::application-menu/layout-menus.png[width="800px"]

This is done using the xref:refguide:applib:index/annotation/DomainServiceLayout.adoc#menuBar[@DomainServiceLayout#menuBar()] annotation.

For example:

[source,java]
----
@DomainService(
        nature = NatureOfService.VIEW,                              // <.>
        objectType = "simple.SimpleObjects"
        )
@DomainServiceLayout(menuBar = DomainServiceLayout.MenuBar.PRIMARY) // <.>
public class SimpleObjects {
    // ...
}
----
<.> Domain service with actions visible in the UI
<.> Menu for the service added to the primary menu bar.

The tertiary menu bar consists of a single unnamed menu, rendered underneath the user's login, top right.
This is intended primarily for actions pertaining to the user themselves, eg their account, profile or settings:

image::application-menu/tertiary.png[width="300px"]



In addition, the xref:refguide:applib:index/annotation/ActionLayout.adoc[@ActionLayout] annotation can be used to group and order domain service actions:

* `@ActionLayout#named()` is used to define the name of the menu
+
in which the menu items of the domain service action will appear

* `@ActionLayout#sequence()` is used to order menu items within that menu.

Thus, using `named()` it's possible to group menu items from actions that are from different domain services.

There are some significant limitations, however:

* domain services are added to the menu bar alphabetically.
This cannot be controlled using annotations.
* there is no way to order or group menu items from multiple domain services that appear on the same menu.

The annotation based approach is therefore useful during very early prototyping, but in real-world applications you should use xref:ui.adoc#file-based-menus[file based] menu layouts.


[[file-based-menus]]
== `menubars.layout.xml`

Rather than use annotations to specify the location of menu items corresponding to the domain services' actions, the framework instead allow domain service actions to be arranged  using the `menubars.layout.xml` file.

This offers a number of benefits:

* Probably most significantly, the layout can be updated without requiring a recompile of the code and redeploy of the app; fine-tuning the layout with your end users is easy to do

* You'll probably find it easier to reason about menu bars layout when all the hints are collated together in a single place (rather than scattered across the domain service classes as annotations).

There are some disadvantages to using file-based layouts:

* file-based layouts are not typesafe: a typo will result in the metadata not being picked up for the element.

* they also suffer from syntactic fragility: an invalid XML document could result in no metadata for the entire class.

The `menubars.layout.xml` file is just the serialized form of a xref:refguide:applib-classes:layout/menubars.adoc[MenuBars] layout class defined within Apache Isis' applib.
These are JAXB-annotated classes with corresponding XSD schemas; the upshot of that
is that IDEs such as IntelliJ and Eclipse can provide "intellisense", making it easy to author such layout files.



For example, here's a fragment of that provided by the xref:docs:starters:simpleapp.adoc[SimpleApp] starter app:

[source,xml]
----
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mb3:menuBars
    xsi:schemaLocation="..."
    xmlns:cpt="http://isis.apache.org/applib/layout/component"
    xmlns:lnk="http://isis.apache.org/applib/layout/links"
    xmlns:mb3="http://isis.apache.org/applib/layout/menubars/bootstrap3"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <mb3:primary>                                               <!--.-->
        <mb3:menu>                                              <!--.-->
            <mb3:named>Simple Objects</mb3:named>
            <mb3:section>                                       <!--.-->
                <mb3:serviceAction                              <!--.-->
                        objectType="simple.SimpleObjects"       <!--.-->
                        id="create">
                    <cpt:named>Create</cpt:named>               <!--.-->
                </mb3:serviceAction>
                <mb3:serviceAction
                        objectType="simple.SimpleObjects"
                        id="findByName">
                    <cpt:named>Find By Name</cpt:named>
                </mb3:serviceAction>
                <mb3:serviceAction
                        objectType="simple.SimpleObjects"
                        id="listAll">
                    <cpt:named>List All</cpt:named>
                </mb3:serviceAction>
            </mb3:section>
        </mb3:menu>
        <mb3:menu unreferencedActions="true">                   <!--.-->
            <mb3:named>Other</mb3:named>
        </mb3:menu>
    </mb3:primary>
    <mb3:secondary>                                             <!--.-->
        <mb3:menu>
            <mb3:named>Prototyping</mb3:named>
            ...
    </mb3:secondary>
    <mb3:tertiary>                                              <!--.-->
        <mb3:menu>
            ...
        </mb3:menu>
    </mb3:tertiary>
</mb3:menuBars>
----
<.> Primary menu bar.
<.> Menu on the menu bar
<.> References an action of a domain service
<.> Divider is placed between each section
<.> Identifies the service through its xref:refguide:applib:index/annotation/DomainService.adoc#logicalTypeName[logical type name]
<.> Optionally override the name inferred from the action
<.> Domain service actions not specified elsewhere are displayed on the "Other" menu (with `unreferencedActions` attribute set to `true`). +
+
IMPORTANT: For a layout file to be valid there must be exactly one `<menu>` with the
`unreferencedActions` attribute set.
<.> Secondary menu bar.
<.> Tertiary menu bar.


Any domain service actions that are not explicitly listed will be placed under this menu.

The downloaded `menubars.layout.xml` file can be adjusted as necessary, creating new menus and menu sections.
Once done, it can be saved and the project rebuilt in the IDE.
If running in prototype mode, the file will be dynamically reloaded from the classpath.

Once the application has bootstrapped with a layout file, downloading the "Default" layout (from the prototyping menu) in essence just returns this file.


=== Prototyping menu

The framework provides a large number of menu actions available in prototyping mode.
You can use `menubars.layout.xml` to arrange these as you see fit, though our recommendation is to place them all in a "Prototyping" secondary menu:

[source,xml]
.menubars.layout.xml
----
<mb3:secondary>
    <mb3:menu>
        <mb3:named>Prototyping</mb3:named>
        <mb3:section>
            <mb3:named>Fixtures</mb3:named>
            <mb3:serviceAction objectType="isis.testing.fixtures.FixtureScripts" id="runFixtureScript"/>
            <mb3:serviceAction objectType="isis.testing.fixtures.FixtureScripts" id="recreateObjectsAndReturnFirst"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>Layouts</mb3:named>
            <mb3:serviceAction objectType="isis.applib.LayoutServiceMenu" id="downloadLayouts"/>
            <mb3:serviceAction objectType="isis.applib.LayoutServiceMenu" id="downloadMenuBarsLayout"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>Meta Model and Features</mb3:named>
            <mb3:serviceAction objectType="isis.applib.MetaModelServiceMenu" id="downloadMetaModelXml"/>
            <mb3:serviceAction objectType="isis.applib.MetaModelServiceMenu" id="downloadMetaModelCsv"/>
            <mb3:serviceAction objectType="isis.feat.ApplicationFeatureMenu" id="allNamespaces"/>
            <mb3:serviceAction objectType="isis.feat.ApplicationFeatureMenu" id="allTypes"/>
            <mb3:serviceAction objectType="isis.feat.ApplicationFeatureMenu" id="allActions"/>
            <mb3:serviceAction objectType="isis.feat.ApplicationFeatureMenu" id="allProperties"/>
            <mb3:serviceAction objectType="isis.feat.ApplicationFeatureMenu" id="allCollections"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>Persistence</mb3:named>
            <mb3:serviceAction objectType="isis.persistence.jdo.JdoMetamodelMenu" id="downloadMetamodels"/>
            <mb3:serviceAction objectType="isis.ext.h2Console.H2ManagerMenu" id="openH2Console"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>REST API</mb3:named>
            <mb3:serviceAction objectType="isis.viewer.restfulobjects.SwaggerServiceMenu" id="openSwaggerUi"/>
            <mb3:serviceAction objectType="isis.viewer.restfulobjects.SwaggerServiceMenu" id="openRestApi"/>
            <mb3:serviceAction objectType="isis.viewer.restfulobjects.SwaggerServiceMenu" id="downloadSwaggerSchemaDefinition"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>i18n</mb3:named>
            <mb3:serviceAction objectType="isis.applib.TranslationServicePoMenu" id="downloadTranslations"/>
            <mb3:serviceAction objectType="isis.applib.TranslationServicePoMenu" id="resetTranslationCache"/>
            <mb3:serviceAction objectType="isis.applib.TranslationServicePoMenu" id="switchToReadingTranslations"/>
            <mb3:serviceAction objectType="isis.applib.TranslationServicePoMenu" id="switchToWritingTranslations"/>
        </mb3:section>
    </mb3:menu>
</mb3:secondary>
----


=== Tertiary menu

The framework also provides a number of menu actions available in production (as oppposed to prototyping) mode.
You can use `menubars.layout.xml` to arrange these as you see fit, though our recommendation is to place them in the tertiary menu:

[source,xml]
.menubars.layout.xml
----
<mb3:tertiary>
    <mb3:menu>
        <mb3:named/>
        <mb3:section>
            <mb3:named>Configuration</mb3:named>
            <mb3:serviceAction objectType="isis.conf.ConfigurationMenu" id="configuration"/>
        </mb3:section>
        <mb3:section>
            <mb3:named>Impersonate</mb3:named>
            <mb3:serviceAction objectType="isis.sudo.ImpersonateMenu" id="impersonate"/>
            <mb3:serviceAction objectType="isis.sudo.ImpersonateMenu" id="impersonateWithRoles"/>
            <mb3:serviceAction objectType="isis.applib.ImpersonateStopMenu" id="stopImpersonating"/>
        </mb3:section>
        <mb3:section>
            <mb3:serviceAction objectType="isis.security.LogoutMenu" id="logout"/>
        </mb3:section>
    </mb3:menu>
</mb3:tertiary>
----



=== Downloading the layout file

The current `menubars.layout.xml` can be downloaded from the xref:refguide:applib:index/services/menu/MenuBarsService.adoc[MenuBarsService] (exposed on the prototyping menu):

image::menubars/010-download.png[width="300px"]

If there are unknown/unreferenced actions in the "Other" menu (which you would like to place elsewhere), then these will be listed in the downloaded layout, so they can easily be moved elsewhere.
