feat: allow sageclient startup URL

This commit is contained in:
yumoqing 2026-05-18 23:49:55 +08:00
parent 388272b4ed
commit 87ebf5a407
2 changed files with 71 additions and 2 deletions

View File

@ -35,6 +35,8 @@ Extra Gradle arguments can be appended, for example:
## Run ## Run
Run without arguments to open the sample shell:
```bash ```bash
cd /path/to/bricks-mp/test/sageclient cd /path/to/bricks-mp/test/sageclient
../../gradlew run \ ../../gradlew run \
@ -42,6 +44,21 @@ cd /path/to/bricks-mp/test/sageclient
-Dsage.centerUi=/center.ui -Dsage.centerUi=/center.ui
``` ```
Run with a startup URL to enter that UI directly:
```bash
cd /path/to/bricks-mp/test/sageclient
../../gradlew run --args="https://ai.atvoe.com/center.ui"
```
The packaged macOS app also accepts the URL as its first argument:
```bash
open build/compose/binaries/main/app/sageclient.app --args https://ai.atvoe.com/center.ui
```
If the argument is an absolute `http://` or `https://` URL, `sageclient` uses the URL origin as `baseUrl` and loads the path/query part as the initial Bricks UI. If the argument is a relative path such as `/center.ui`, it uses `sage.baseUrl` and loads that path.
Optional properties: Optional properties:
- `sage.baseUrl` defaults to `http://localhost:8080` - `sage.baseUrl` defaults to `http://localhost:8080`

View File

@ -51,14 +51,21 @@ private const val DEFAULT_CENTER_UI = "/center.ui"
private const val DEFAULT_LOGIN_ACTION = "/rbac/user/login" private const val DEFAULT_LOGIN_ACTION = "/rbac/user/login"
private const val DEFAULT_LOGIN_UI = "/rbac/user/login.ui" private const val DEFAULT_LOGIN_UI = "/rbac/user/login.ui"
fun main() = application { fun main(args: Array<String>) = application {
val context = remember { BricksContext() } val context = remember { BricksContext() }
val http = remember { BricksHttp(context) } val http = remember { BricksHttp(context) }
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val windowState = remember { WindowState(width = 1280.dp, height = 800.dp) } val windowState = remember { WindowState(width = 1280.dp, height = 800.dp) }
val startupUrl = remember(args) { args.firstOrNull()?.takeIf { it.isNotBlank() } }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
context.baseUrl = System.getProperty("sage.baseUrl", DEFAULT_BASE_URL) val initialUrl = startupUrl
if (initialUrl != null) {
configureContextFromStartupUrl(context, initialUrl)
} else {
context.baseUrl = System.getProperty("sage.baseUrl", DEFAULT_BASE_URL)
}
} }
Window( Window(
@ -115,6 +122,19 @@ fun main() = application {
} }
val currentWidget by context.currentWidget.collectAsState() val currentWidget by context.currentWidget.collectAsState()
LaunchedEffect(actionDispatcher, startupUrl) {
startupUrl?.let { url ->
actionDispatcher.dispatch(
BricksBind(
event = "startup",
actiontype = "urlwidget",
url = toWidgetPath(url)
)
)
}
}
SageClientScreen( SageClientScreen(
baseUrl = context.baseUrl, baseUrl = context.baseUrl,
widget = currentWidget, widget = currentWidget,
@ -246,6 +266,38 @@ private fun SageClientScreen(
} }
} }
private fun configureContextFromStartupUrl(context: BricksContext, startupUrl: String) {
if (startupUrl.startsWith("http://") || startupUrl.startsWith("https://")) {
context.baseUrl = startupUrl.originPart()
} else {
context.baseUrl = System.getProperty("sage.baseUrl", DEFAULT_BASE_URL)
}
}
private fun toWidgetPath(startupUrl: String): String {
if (!startupUrl.startsWith("http://") && !startupUrl.startsWith("https://")) return startupUrl
val pathWithQuery = startupUrl.pathAndQueryPart()
return pathWithQuery.ifBlank { "/" }
}
private fun String.originPart(): String {
val schemeEnd = indexOf("://")
if (schemeEnd < 0) return ""
val authorityStart = schemeEnd + 3
val authorityEnd = indexOf('/', startIndex = authorityStart).let { if (it < 0) length else it }
return substring(0, authorityEnd)
}
private fun String.pathAndQueryPart(): String {
val schemeEnd = indexOf("://")
val pathStart = if (schemeEnd >= 0) {
indexOf('/', startIndex = schemeEnd + 3).let { if (it < 0) return "" else it }
} else {
0
}
return substring(pathStart).substringBefore('#')
}
private suspend fun loginAndLoadCenter( private suspend fun loginAndLoadCenter(
context: BricksContext, context: BricksContext,
http: BricksHttp, http: BricksHttp,