Skip to content

Commit

Permalink
Add index, fix links
Browse files Browse the repository at this point in the history
  • Loading branch information
adrw committed Jan 12, 2025
1 parent 726af0c commit 31a5348
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 93 deletions.
2 changes: 2 additions & 0 deletions service/src/main/kotlin/app/cash/backfila/ui/UiModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package app.cash.backfila.ui
import app.cash.backfila.ui.actions.BackfillShowButtonHandlerAction
import app.cash.backfila.ui.actions.ServiceAutocompleteAction
import app.cash.backfila.ui.pages.BackfillShowAction
import app.cash.backfila.ui.pages.IndexAction
import app.cash.backfila.ui.pages.ServiceIndexAction
import app.cash.backfila.ui.pages.ServiceShowAction
import misk.inject.KAbstractModule
Expand All @@ -11,6 +12,7 @@ import misk.web.WebActionModule
class UiModule : KAbstractModule() {
override fun configure() {
// Pages
install(WebActionModule.create<IndexAction>())
install(WebActionModule.create<ServiceShowAction>())
install(WebActionModule.create<ServiceIndexAction>())
install(WebActionModule.create<BackfillShowAction>())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import misk.tailwind.Link
import misk.tailwind.pages.MenuSection
import misk.tailwind.pages.Navbar
import misk.web.HttpCall
import misk.web.ResponseBody
import misk.web.dashboard.DashboardHomeUrl
import misk.web.dashboard.DashboardNavbarItem
import misk.web.dashboard.DashboardTab
import misk.web.dashboard.HtmlLayout
import okio.BufferedSink
import wisp.deployment.Deployment

/**
Expand All @@ -32,10 +34,6 @@ import wisp.deployment.Deployment
* Must be called within a Web Action.
*/
class DashboardPageLayout @Inject constructor(
private val allHomeUrls: List<DashboardHomeUrl>,
@AppName private val appName: String,
private val allNavbarItem: List<DashboardNavbarItem>,
private val allTabs: List<DashboardTab>,
private val callerProvider: ActionScoped<MiskCaller?>,
private val deployment: Deployment,
private val clientHttpCall: ActionScoped<HttpCall>,
Expand All @@ -50,20 +48,10 @@ class DashboardPageLayout @Inject constructor(
private val path by lazy {
clientHttpCall.get().url.encodedPath
}
private val dashboardHomeUrl by lazy {
allHomeUrls.firstOrNull { path.startsWith(it.url) }
}
private val homeUrl by lazy {
dashboardHomeUrl?.url ?: "/"
}

private fun setNewBuilder() = apply { newBuilder = true }

fun newBuilder(): DashboardPageLayout = DashboardPageLayout(
allHomeUrls = allHomeUrls,
appName = appName,
allNavbarItem = allNavbarItem,
allTabs = allTabs,
callerProvider = callerProvider,
deployment = deployment,
clientHttpCall = clientHttpCall,
Expand Down Expand Up @@ -104,29 +92,16 @@ class DashboardPageLayout @Inject constructor(
},
) {
div("min-h-full") {
if (true) {
// Uses Misk's Navbar with sidebar
Navbar(
appName = "Backfila",
deployment = deployment,
homeHref = "/",
menuSections = buildMenuSections(
currentPath = path,
),
) {
div("py-10") {
main {
div("mx-auto max-w-7xl sm:px-6 lg:px-8") {
// TODO remove when new UI is stable and preferred
UseOldUIAlert()
block()
}
}
}
}
} else {
// Old UI
NavBar(path)
// Uses Misk's Navbar with sidebar
Navbar(
appName = "Backfila",
deployment = deployment,
homeHref = "/",
menuSections = buildMenuSections(
currentPath = path,
),
sortedMenuLinks = false,
) {
div("py-10") {
main {
div("mx-auto max-w-7xl sm:px-6 lg:px-8") {
Expand All @@ -142,55 +117,78 @@ class DashboardPageLayout @Inject constructor(
}
}

fun buildHtmlResponseBody(block: TagConsumer<*>.() -> Unit): ResponseBody = object : ResponseBody {
override fun writeTo(sink: BufferedSink) {
sink.writeUtf8(build(block))
}
}

private fun buildMenuSections(
currentPath: String,
): List<MenuSection> {
return transacter.transaction { session ->
val runningBackfills = queryFactory.newQuery<BackfillRunQuery>()
val runningBackfillsForCaller = queryFactory.newQuery<BackfillRunQuery>()
.createdByUser(callerProvider.get()!!.user!!)
.state(BackfillState.RUNNING)
.orderByUpdatedAtDesc()
.list(session)

// TODO get services from REgistry for user || group backfills by service
val services = runningBackfillsForCaller.groupBy { it.service }

listOf(
MenuSection(
title = "Backfila",
links = listOf(
Link(
label = "Home",
href = "/",
isSelected = currentPath == "/",
),
Link(
label = "Services",
href = "/services/",
isSelected = currentPath.startsWith("/services/"),
isSelected = currentPath == "/services/",
),
Link(
label = "Backfills",
href = "/backfills/",
isSelected = currentPath.startsWith("/backfills/"),
isSelected = currentPath == "/backfills/",
),
),
),
MenuSection(
title = "Your Services",
links = listOf(
Link(
label = "Fine Dining",
href = "/services/?q=FineDining",
isSelected = currentPath.startsWith("/services/?q=FindDining"),
),
) + if (services.isNotEmpty()) {
listOf(
MenuSection(
title = "Your Services",
links = services.map { (service, backfills) ->
val variant = if (service.variant == "default") "" else service.variant
Link(
label = service.registry_name,
href = "/services/${service.registry_name}/$variant",
isSelected = currentPath.startsWith("/services/${service.registry_name}/$variant"),
)
},
),
),
MenuSection(
title = "Your Backfills",
links = runningBackfills.map { backfill ->
Link(
label = backfill.service.registry_name + " #" + backfill.id,
href = "/backfills/${backfill.id}",
isSelected = currentPath.startsWith("/backfills/${backfill.id}"),
)
},
),
)
)
} else {
listOf()
} + if (runningBackfillsForCaller.isNotEmpty()) {
listOf(
MenuSection(
title = "Your Backfills",
links = runningBackfillsForCaller.map { backfill ->
Link(
label = backfill.service.registry_name + " #" + backfill.id,
href = "/backfills/${backfill.id}",
isSelected = currentPath.startsWith("/backfills/${backfill.id}"),
)
},
),
)
} else {
listOf()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import app.cash.backfila.service.persistence.BackfillState
import app.cash.backfila.ui.actions.BackfillShowButtonHandlerAction
import app.cash.backfila.ui.components.AlertError
import app.cash.backfila.ui.components.AlertSupport
import app.cash.backfila.ui.components.DashboardLayout
import app.cash.backfila.ui.components.DashboardPageLayout
import app.cash.backfila.ui.components.PageTitle
import app.cash.backfila.ui.components.ProgressBar
import javax.inject.Inject
Expand All @@ -30,7 +30,6 @@ import kotlinx.html.td
import kotlinx.html.th
import kotlinx.html.thead
import kotlinx.html.tr
import misk.hotwire.buildHtmlResponseBody
import misk.security.authz.Authenticated
import misk.tailwind.Link
import misk.web.Get
Expand All @@ -45,6 +44,7 @@ import misk.web.mediatype.MediaTypes
class BackfillShowAction @Inject constructor(
private val config: BackfilaConfig,
private val getBackfillStatusAction: GetBackfillStatusAction,
private val dashboardPageLayout: DashboardPageLayout,
) : WebAction {
@Get(PATH)
@ResponseContentType(MediaTypes.TEXT_HTML)
Expand All @@ -54,25 +54,20 @@ class BackfillShowAction @Inject constructor(
): Response<ResponseBody> {
if (id.toLongOrNull() == null) {
return Response(
buildHtmlResponseBody {
DashboardLayout(
title = "Backfill $id | Backfila",
path = PATH,
) {
dashboardPageLayout.newBuilder()
.title("Backfill $id | Backfila")
.buildHtmlResponseBody {
PageTitle("Backfill", id)
AlertError("Invalid Backfill Id [id=$id], must be of type Long.")
AlertSupport(config.support_button_label, config.support_button_url)
}
},
},
)
}
val backfill = getBackfillStatusAction.status(id.toLong())

val htmlResponseBody = buildHtmlResponseBody {
DashboardLayout(
title = "Backfill $id | Backfila",
path = PATH,
) {
val htmlResponseBody = dashboardPageLayout.newBuilder()
.title("Backfill $id | Backfila")
.buildHtmlResponseBody {
PageTitle("Backfill", id)

// TODO add Header buttons / metrics
Expand Down Expand Up @@ -306,7 +301,6 @@ class BackfillShowAction @Inject constructor(

AlertSupport(config.support_button_label, config.support_button_url)
}
}

return Response(htmlResponseBody)
}
Expand Down
73 changes: 73 additions & 0 deletions service/src/main/kotlin/app/cash/backfila/ui/pages/IndexAction.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package app.cash.backfila.ui.pages

import app.cash.backfila.service.BackfilaConfig
import app.cash.backfila.ui.actions.ServiceAutocompleteAction
import app.cash.backfila.ui.components.AlertSupport
import app.cash.backfila.ui.components.DashboardPageLayout
import javax.inject.Inject
import kotlinx.html.dd
import kotlinx.html.div
import kotlinx.html.dl
import kotlinx.html.dt
import kotlinx.html.h1
import kotlinx.html.h3
import kotlinx.html.span
import misk.MiskCaller
import misk.scope.ActionScoped
import misk.security.authz.Authenticated
import misk.web.Get
import misk.web.QueryParam
import misk.web.ResponseContentType
import misk.web.actions.WebAction
import misk.web.mediatype.MediaTypes

class IndexAction @Inject constructor(
private val config: BackfilaConfig,
private val serviceAutocompleteAction: ServiceAutocompleteAction,
private val dashboardPageLayout: DashboardPageLayout,
private val callerProvider: ActionScoped<MiskCaller?>,
) : WebAction {
@Get(PATH)
@ResponseContentType(MediaTypes.TEXT_HTML)
@Authenticated(capabilities = ["users"])
fun get(
@QueryParam sc: String?,
): String = dashboardPageLayout
.newBuilder()
.title("Backfila Home")
.build {
h1("text-2xl") {
+"""Welcome to Backfila, """
span("font-bold font-mono") { +"""${callerProvider.get()?.user}""" }
+"""!"""
}

// Stats

div("py-10") {
h3("text-base font-semibold text-gray-900") { +"""Last 30 days""" }
dl("mt-5 grid grid-cols-1 gap-5 sm:grid-cols-3") {
div("overflow-hidden rounded-lg bg-white px-4 py-5 shadow sm:p-6") {
this@dl.dt("truncate text-sm font-medium text-gray-500") { +"""Total Records""" }
this@dl.dd("mt-1 text-3xl font-semibold tracking-tight text-gray-900") { +"""1,271,897""" }
}
div("overflow-hidden rounded-lg bg-white px-4 py-5 shadow sm:p-6") {
this@dl.dt("truncate text-sm font-medium text-gray-500") { +"""Avg. Progress Rate""" }
this@dl.dd("mt-1 text-3xl font-semibold tracking-tight text-gray-900") { +"""58.16%""" }
}
div("overflow-hidden rounded-lg bg-white px-4 py-5 shadow sm:p-6") {
this@dl.dt("truncate text-sm font-medium text-gray-500") { +"""Avg. Records Per Second""" }
this@dl.dd("mt-1 text-3xl font-semibold tracking-tight text-gray-900") { +"""2457""" }
}
}
}

// Running Backfills

AlertSupport(config.support_button_label, config.support_button_url)
}

companion object {
const val PATH = "/"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,6 @@ class ServiceIndexAction @Inject constructor(
}

companion object {
const val PATH = "/"
const val PATH = "/services/"
}
}
Loading

0 comments on commit 31a5348

Please sign in to comment.