Skip to content

Commit 6e4769c

Browse files
committed
Add breadcrumbs
1 parent 549d852 commit 6e4769c

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-1
lines changed

service/src/main/kotlin/app/cash/backfila/ui/components/DashboardPageLayout.kt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,27 @@ import app.cash.backfila.service.BackfilaConfig
55
import app.cash.backfila.service.persistence.BackfilaDb
66
import app.cash.backfila.service.persistence.BackfillRunQuery
77
import app.cash.backfila.service.persistence.BackfillState
8+
import app.cash.backfila.ui.pages.IndexAction
89
import jakarta.inject.Inject
910
import kotlinx.html.TagConsumer
11+
import kotlinx.html.a
1012
import kotlinx.html.div
13+
import kotlinx.html.li
1114
import kotlinx.html.main
15+
import kotlinx.html.nav
16+
import kotlinx.html.ol
17+
import kotlinx.html.role
1218
import kotlinx.html.script
19+
import kotlinx.html.span
1320
import misk.MiskCaller
1421
import misk.hibernate.Query
1522
import misk.hibernate.Transacter
1623
import misk.hibernate.newQuery
1724
import misk.hotwire.buildHtml
1825
import misk.scope.ActionScoped
1926
import misk.tailwind.Link
27+
import misk.tailwind.icons.Heroicons
28+
import misk.tailwind.icons.heroicon
2029
import misk.tailwind.pages.MenuSection
2130
import misk.tailwind.pages.Navbar
2231
import misk.web.HttpCall
@@ -42,6 +51,7 @@ class DashboardPageLayout @Inject constructor(
4251
private var newBuilder = false
4352
private var headBlock: TagConsumer<*>.() -> Unit = {}
4453
private var title: String = "Backfila"
54+
private var breadcrumbLinks: List<Link> = listOf()
4555

4656
private val path by lazy {
4757
clientHttpCall.get().url.encodedPath
@@ -65,6 +75,8 @@ class DashboardPageLayout @Inject constructor(
6575

6676
fun headBlock(block: TagConsumer<*>.() -> Unit) = apply { this.headBlock = block }
6777

78+
fun breadcrumbLinks(links: List<Link>) = apply { this.breadcrumbLinks = links }
79+
6880
@JvmOverloads
6981
fun build(block: TagConsumer<*>.() -> Unit = { }): String {
7082
check(newBuilder) {
@@ -112,6 +124,10 @@ class DashboardPageLayout @Inject constructor(
112124
// TODO remove when new UI is stable and preferred
113125
UseOldUIAlert()
114126

127+
if (breadcrumbLinks.isNotEmpty()) {
128+
Breadcrumbs(breadcrumbLinks)
129+
}
130+
115131
block()
116132

117133
AlertSupport(config.support_button_label, config.support_button_url)
@@ -202,6 +218,37 @@ class DashboardPageLayout @Inject constructor(
202218
}
203219
}
204220

221+
private fun TagConsumer<*>.Breadcrumbs(links: List<Link>) {
222+
nav("flex") {
223+
attributes["aria-label"] = "Breadcrumb"
224+
ol("flex items-center space-x-4") {
225+
role = "list"
226+
li {
227+
div {
228+
a(classes = "text-gray-400 hover:text-gray-500") {
229+
href = IndexAction.PATH
230+
231+
heroicon(Heroicons.OUTLINE_HOME)
232+
span("sr-only") { +"""Home""" }
233+
}
234+
}
235+
}
236+
links.forEach {
237+
li {
238+
div("flex items-center") {
239+
// TODO upstream chevron_right and use instead
240+
heroicon(Heroicons.MINI_ARROW_LONG_RIGHT)
241+
a(classes = "ml-4 text-sm font-medium text-gray-500 hover:text-gray-700") {
242+
href = it.href
243+
+it.label
244+
}
245+
}
246+
}
247+
}
248+
}
249+
}
250+
}
251+
205252
companion object {
206253
}
207254
}

service/src/main/kotlin/app/cash/backfila/ui/pages/BackfillShowAction.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,16 @@ class BackfillShowAction @Inject constructor(
5151
@PathParam id: String,
5252
): Response<ResponseBody> {
5353
val backfill = getBackfillStatusAction.status(id.toLong())
54+
val label = if (backfill.variant == "default") backfill.service_name else "${backfill.service_name} (${backfill.variant})"
5455

5556
val htmlResponseBody = dashboardPageLayout.newBuilder()
5657
.title("Backfill $id | Backfila")
58+
.breadcrumbLinks(
59+
listOf(
60+
Link(label, ServiceShowAction.PATH.replace("{service}", backfill.service_name).replace("{variantOrBlank}", if (backfill.variant != "default") backfill.variant else "")),
61+
Link("Backfill $id", PATH.replace("{id}", id)),
62+
),
63+
)
5764
.buildHtmlResponseBody {
5865
AutoReload {
5966
PageTitle("Backfill", id) {

service/src/main/kotlin/app/cash/backfila/ui/pages/ServiceShowAction.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import kotlinx.html.a
1313
import kotlinx.html.button
1414
import misk.scope.ActionScoped
1515
import misk.security.authz.Authenticated
16+
import misk.tailwind.Link
1617
import misk.tokens.TokenGenerator
1718
import misk.web.Get
1819
import misk.web.HttpCall
@@ -58,11 +59,18 @@ class ServiceShowAction @Inject constructor(
5859
val label = if (variant == "default") service else "$service ($variant)"
5960
val htmlResponseBody = dashboardPageLayout.newBuilder()
6061
.title("$label | Backfila")
62+
.breadcrumbLinks(
63+
listOf(
64+
Link("Services", ServiceIndexAction.PATH),
65+
Link(label, path),
66+
),
67+
)
6168
.buildHtmlResponseBody {
6269
AutoReload {
6370
PageTitle("Service", label) {
6471
a {
65-
href = BackfillCreateAction.PATH.replace("{service}", service).replace("{variantOrBlank}", variantOrBlank ?: "")
72+
href = BackfillCreateAction.PATH.replace("{service}", service)
73+
.replace("{variantOrBlank}", variantOrBlank ?: "")
6674

6775
button(classes = "rounded-full bg-indigo-600 px-3 py-1.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600") {
6876
type = ButtonType.button

0 commit comments

Comments
 (0)