Extend the UI
Linking / Embedding External Pages in Navbarβ
Links will be opened in a new window/tab (i.e. target="_blank"
) having no access to opener and referrer (rel="noopener noreferrer"
).
Simple linkβ
To add a simple link to an external page, use the following snippet.
spring:
boot:
admin:
ui:
external-views:
- label: "π" #(1)
url: "https://codecentric.de" #(2)
order: 2000 #(3)
- The label will be shown in the navbar
- URL to the page you want to link to
- Order that allows to specify position of item in navbar
Dropdown with linksβ
To aggregate links below a single element, dropdowns can be configured as follows.
spring:
boot:
admin:
ui:
external-views:
- label: Link w/o children
children:
- label: "π Docs"
url: https://codecentric.github.io/spring-boot-admin/current/
- label: "π¦ Maven"
url: https://search.maven.org/search?q=g:de.codecentric%20AND%20a:spring-boot-admin-starter-server
- label: "π GitHub"
url: https://github.com/codecentric/spring-boot-admin
Dropdown as link having links as childrenβ
spring:
boot:
admin:
ui:
external-views:
- label: Link w children
url: https://codecentric.de #(1)
children:
- label: "π Docs"
url: https://codecentric.github.io/spring-boot-admin/current/
- label: "π¦ Maven"
url: https://search.maven.org/search?q=g:de.codecentric%20AND%20a:spring-boot-admin-starter-server
- label: "π GitHub"
url: https://github.com/codecentric/spring-boot-admin
- label: "π
Is it christmas"
url: https://isitchristmas.com
iframe: true
Custom Viewsβ
It is possible to add custom views to the ui. The views must be implemented as Vue.js components.
The JavaScript-Bundle and CSS-Stylesheet must be placed on the classpath at /META-INF/spring-boot-admin-server-ui/extensions/{name}/
so the server can pick them up. The spring-boot-admin-sample-custom-ui module contains a sample which has the necessary maven setup to build such a module.
The custom extension registers itself by calling:
SBA.use({
install({ viewRegistry, i18n }) {
viewRegistry.addView({
name: "custom", //(1)
path: "/custom", //(2)
component: custom, //(3)
group: "custom", //(4)
handle, //(5)
order: 1000, //(6)
});
i18n.mergeLocaleMessage("en", {
custom: {
label: "My Extensions", //(7)
},
});
i18n.mergeLocaleMessage("de", {
custom: {
label: "Meine Erweiterung",
},
});
},
});
- Name of the view and the route.
- Path in Vue router.
- The imported custom component, which will be rendered on the route.
- An optional group name that allows to bind views to a logical group (defaults to "none")
- The handle for the custom view to be shown in the top navigation bar.
- Order for the view.
- Using
i18n.mergeLocaleMessage
allows to add custom translations.
Views in the top navigation bar are sorted by ascending order.
If new top level routes are added to the frontend, they also must be known to the backend. Add a /META-INF/spring-boot-admin-server-ui/extensions/{name}/routes.txt
with all your new toplevel routes (one route per line).
Groups are used in instance sidebar to aggregate multiple views into a collapsible menu entry showing the groupβs name. When a group contains just a single element, the label of the view is shown instead of the groupβs name.
Override/Set custom group iconsβ
In order to override or set icons for (custom) groups you can use the SBA.viewRegistry.setGroupIcon
function as follows:
SBA.viewRegistry.setGroupIcon(
"custom", //(1)
`<svg xmlns='http://www.w3.org/2000/svg'
class='h-5 mr-3'
viewBox='0 0 576 512'><path d='M512 80c8.8 0 16 7.2 16 16V416c0 8.8-7.2 16-16 16H64c-8.8 0-16-7.2-16-16V96c0-8.8 7.2-16 16-16H512zM64 32C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64H512c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zM200 208c14.2 0 27 6.1 35.8 16c8.8 9.9 24 10.7 33.9 1.9s10.7-24 1.9-33.9c-17.5-19.6-43.1-32-71.5-32c-53 0-96 43-96 96s43 96 96 96c28.4 0 54-12.4 71.5-32c8.8-9.9 8-25-1.9-33.9s-25-8-33.9 1.9c-8.8 9.9-21.6 16-35.8 16c-26.5 0-48-21.5-48-48s21.5-48 48-48zm144 48c0-26.5 21.5-48 48-48c14.2 0 27 6.1 35.8 16c8.8 9.9 24 10.7 33.9 1.9s10.7-24 1.9-33.9c-17.5-19.6-43.1-32-71.5-32c-53 0-96 43-96 96s43 96 96 96c28.4 0 54-12.4 71.5-32c8.8-9.9 8-25-1.9-33.9s-25-8-33.9 1.9c-8.8 9.9-21.6 16-35.8 16c-26.5 0-48-21.5-48-48z'/>
</svg>` //(2)
);
- Name of the group to set icon for
- Arbitrary HTML code (e.g. SVG image) that is inserted and parsed as icon.
Adding a Top-Level Viewβ
Here is a simple top level view just listing all registered applications:
<template>
<div class="m-4">
<template v-for="application in applications" :key="application.name">
<sba-panel :title="application.name">
This application has the following instances:
<ul>
<template v-for="instance in application.instances">
<li>
<span class="mx-1" v-text="instance.registration.name"></span>
<!-- SBA components are registered globally and can be used without importing them! -->
<!-- They are defined in spring-boot-admin-server-ui -->
<sba-status :status="instance.statusInfo.status" class="mx-1" />
<sba-tag :value="instance.id" class="mx-1" label="id" />
</li>
</template>
</ul>
</sba-panel>
</template>
<pre v-text="applications"></pre>
</div>
</template>
<script>
/* global SBA */
import "./custom.css";
export default {
setup() {
const { applications } = SBA.useApplicationStore(); //(1)
return {
applications,
};
},
methods: {
stringify: JSON.stringify,
},
};
</script>
- By destructuring
applications
ofSBA.useApplicationStore()
, you have reactive access to registered applications.
There are some helpful methods on the application and instances object available. Have a look at application.ts and instance.ts
And this is how you register the top-level view.
Exampleβ
SBA.viewRegistry.addView({
name: "customSub",
parent: "custom", // (1)
path: "/customSub", // (2)
component: customSubitem,
label: "Custom Sub",
order: 1000,
});
- References the name of the parent view.
- Router path used to navigate to.
- Define whether the path should be registered as child route in parentβs route. When set to
true
, the parent component has to implement<router-view>
The routes.txt
config with the added route:
/custom/**
/customSub/**
Visualizing a Custom Endpointβ
Here is a view to show a custom endpoint:
<template>
<div class="custom">
<p>Instance: <span v-text="instance.id" /></p>
<p>Output: <span v-html="text" /></p>
</div>
</template>
<script>
export default {
props: {
instance: {
//(1)
type: Object,
required: true,
},
},
data: () => ({
text: "",
}),
async created() {
console.log(this.instance);
const response = await this.instance.axios.get("actuator/custom"); //(2)
this.text = response.data;
},
};
</script>
<style lang="css" scoped>
.custom {
font-size: 20px;
width: 80%;
}
</style>
- If you define a
instance
prop the component will receive the instance the view should be rendered for. - Each instance has a preconfigured axios instance to access the endpoints with the correct path and headers.
Registering the instance view works like for the top-level view with some additional properties:
SBA.viewRegistry.addView({
name: "instances/custom",
parent: "instances", // (1)
path: "custom",
component: customEndpoint,
label: "Custom",
group: "custom", // (2)
order: 1000,
isEnabled: ({ instance }) => {
return instance.hasEndpoint("custom");
}, // (3)
});
- The parent must be 'instances' in order to render the new custom view for a single instance.
- You can group views by assigning them to a group.
- If you add a
isEnabled
callback you can figure out dynamically if the view should be show for the particular instance.
You can override default views by putting the same group and name as the one you want to override.