diff --git a/test/sageclient/README.md b/test/sageclient/README.md index 04dad1e..79cf9e6 100644 --- a/test/sageclient/README.md +++ b/test/sageclient/README.md @@ -44,7 +44,8 @@ cd /path/to/bricks-mp/test/sageclient -Dsage.centerUi=/center.ui ``` -Run with a startup URL to enter that UI directly: +Run with a startup URL to enter that UI directly without showing the sample +base URL / login input shell: ```bash cd /path/to/bricks-mp/test/sageclient @@ -57,7 +58,7 @@ The packaged macOS app also accepts the URL as its first argument: 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. The actual HTTP request is still issued through `BricksHttp`, so startup URLs ending in `.ui` / `.dspy` are requested with `_webbricks_=1`, `_width`, `_height`, `_is_mobile` and `_lang`; they must not be fetched as raw HTML/template pages. +If the argument is an absolute `http://` or `https://` URL, `sageclient` uses the URL origin as `baseUrl` and dispatches that same absolute URL through the Bricks `urlwidget` loading path. If the argument is a relative path such as `/center.ui`, it uses `sage.baseUrl` and loads that path. The actual HTTP request is still issued through `BricksHttp`, so startup URLs ending in `.ui` / `.dspy` are requested with `_webbricks_=1`, `_width`, `_height`, `_is_mobile` and `_lang`; they must not be fetched as raw HTML/template pages. Optional properties: diff --git a/test/sageclient/src/jvmMain/kotlin/com/bricks/test/sageclient/Main.kt b/test/sageclient/src/jvmMain/kotlin/com/bricks/test/sageclient/Main.kt index 3832d89..c3d15da 100644 --- a/test/sageclient/src/jvmMain/kotlin/com/bricks/test/sageclient/Main.kt +++ b/test/sageclient/src/jvmMain/kotlin/com/bricks/test/sageclient/Main.kt @@ -123,45 +123,55 @@ fun main(args: Array) = application { val currentWidget by context.currentWidget.collectAsState() - LaunchedEffect(actionDispatcher, startupUrl) { - startupUrl?.let { url -> + val startupTarget = remember(startupUrl) { startupUrl?.let(::toWidgetUrl) } + + LaunchedEffect(actionDispatcher, startupTarget) { + startupTarget?.let { url -> + configureContextFromStartupUrl(context, url) actionDispatcher.dispatch( BricksBind( event = "startup", actiontype = "urlwidget", - url = toWidgetPath(url) + url = url ) ) } } - SageClientScreen( - baseUrl = context.baseUrl, - widget = currentWidget, - actionDispatcher = actionDispatcher, - onBaseUrlChange = { context.baseUrl = it.trimEnd('/') }, - onLoadCenter = { - actionDispatcher.dispatch( - BricksBind( - event = "click", - actiontype = "urlwidget", - url = System.getProperty("sage.centerUi", DEFAULT_CENTER_UI) - ) - ) - }, - onLogin = { username, password -> - scope.launch { - loginAndLoadCenter( - context = context, - http = http, - actionDispatcher = actionDispatcher, - username = username, - password = password, - onMessage = { title, body, isError -> message = Triple(title, body, isError) } + if (startupTarget != null) { + BricksStartupScreen( + widget = currentWidget, + actionDispatcher = actionDispatcher + ) + } else { + SageClientScreen( + baseUrl = context.baseUrl, + widget = currentWidget, + actionDispatcher = actionDispatcher, + onBaseUrlChange = { context.baseUrl = it.trimEnd('/') }, + onLoadCenter = { + actionDispatcher.dispatch( + BricksBind( + event = "click", + actiontype = "urlwidget", + url = System.getProperty("sage.centerUi", DEFAULT_CENTER_UI) + ) ) + }, + onLogin = { username, password -> + scope.launch { + loginAndLoadCenter( + context = context, + http = http, + actionDispatcher = actionDispatcher, + username = username, + password = password, + onMessage = { title, body, isError -> message = Triple(title, body, isError) } + ) + } } - } - ) + ) + } dialogWidget?.let { widget -> AlertDialog( @@ -188,6 +198,27 @@ fun main(args: Array) = application { } } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun BricksStartupScreen( + widget: BricksWidget?, + actionDispatcher: ActionDispatcher +) { + Scaffold { padding -> + Box(modifier = Modifier.padding(padding).fillMaxSize()) { + if (widget == null) { + Text("Loading...") + } else { + RenderWidget( + widget = widget, + actionDispatcher = actionDispatcher, + modifier = Modifier.fillMaxSize() + ) + } + } + } +} + @OptIn(ExperimentalMaterial3Api::class) @Composable private fun SageClientScreen( @@ -274,11 +305,7 @@ private fun configureContextFromStartupUrl(context: BricksContext, startupUrl: S } } -private fun toWidgetPath(startupUrl: String): String { - if (!startupUrl.startsWith("http://") && !startupUrl.startsWith("https://")) return startupUrl - val pathWithQuery = startupUrl.pathAndQueryPart() - return pathWithQuery.ifBlank { "/" } -} +private fun toWidgetUrl(startupUrl: String): String = startupUrl.ifBlank { "/" } private fun String.originPart(): String { val schemeEnd = indexOf("://") @@ -288,16 +315,6 @@ private fun String.originPart(): String { 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( context: BricksContext, http: BricksHttp,