Skip to content

Commit f935888

Browse files
malliaridisepugh
andauthored
SOLR-17658: Implement start screen (#3388)
* Add design for start screen * Add connection logic with error handling * Add SupervisorJob to component scopes * Add component outputs for side effect navigation * Add placeholder for authentication view * Change the way coroutine scopes and context are passed down and initialized * Add test cases for new components * Add DefaultStartComponent integration tests * Cleanup and add test cases * Display loading indicator while connecting * Add missing license headers * Correctly propagate the connection URL to other components * Update solr/ui/src/wasmJsMain/kotlin/org/apache/solr/ui/errors/parseError.kt Co-authored-by: Eric Pugh <epugh@opensourceconnections.com> * Use 127.0.0.1 instead of localhost --------- Co-authored-by: Eric Pugh <epugh@opensourceconnections.com>
1 parent 8a28b91 commit f935888

38 files changed

+1617
-20
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serializa
439439
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
440440
ktor-client-contentNegotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
441441
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
442+
ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktor" }
442443
ktor-client-serialization-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
443444
langchain4j-cohere = { module = "dev.langchain4j:langchain4j-cohere", version.ref = "langchain4j" }
444445
langchain4j-core = { module = "dev.langchain4j:langchain4j-core", version.ref = "langchain4j" }

solr/ui/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ kotlin {
107107
implementation(libs.kotlinx.coroutines.test)
108108
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
109109
implementation(compose.uiTest)
110+
implementation(libs.ktor.client.mock)
110111
}
111112
}
112113

solr/ui/gradle.lockfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ io.ktor:ktor-client-content-negotiation:3.1.0=allSourceSetsCompileDependenciesMe
6666
io.ktor:ktor-client-core-jvm:3.1.0=desktopCompileClasspath,desktopRuntimeClasspath,desktopTestCompileClasspath,desktopTestRuntimeClasspath
6767
io.ktor:ktor-client-core-wasm-js:3.1.0=wasmJsCompileClasspath,wasmJsNpmAggregated,wasmJsRuntimeClasspath,wasmJsTestCompileClasspath,wasmJsTestNpmAggregated,wasmJsTestRuntimeClasspath
6868
io.ktor:ktor-client-core:3.1.0=allSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,commonMainApiDependenciesMetadata,commonMainCompileOnlyDependenciesMetadata,commonMainImplementationDependenciesMetadata,commonMainResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,desktopCompileClasspath,desktopMainApiDependenciesMetadata,desktopMainCompileOnlyDependenciesMetadata,desktopMainImplementationDependenciesMetadata,desktopMainResolvableDependenciesMetadata,desktopRuntimeClasspath,desktopTestApiDependenciesMetadata,desktopTestCompileClasspath,desktopTestCompileOnlyDependenciesMetadata,desktopTestImplementationDependenciesMetadata,desktopTestResolvableDependenciesMetadata,desktopTestRuntimeClasspath,metadataCommonMainCompileClasspath,metadataCompileClasspath,wasmJsCompileClasspath,wasmJsMainApiDependenciesMetadata,wasmJsMainCompileOnlyDependenciesMetadata,wasmJsMainImplementationDependenciesMetadata,wasmJsMainResolvableDependenciesMetadata,wasmJsNpmAggregated,wasmJsRuntimeClasspath,wasmJsTestApiDependenciesMetadata,wasmJsTestCompileClasspath,wasmJsTestCompileOnlyDependenciesMetadata,wasmJsTestImplementationDependenciesMetadata,wasmJsTestNpmAggregated,wasmJsTestResolvableDependenciesMetadata,wasmJsTestRuntimeClasspath
69+
io.ktor:ktor-client-mock-jvm:3.1.0=desktopTestCompileClasspath,desktopTestRuntimeClasspath
70+
io.ktor:ktor-client-mock-wasm-js:3.1.0=wasmJsTestCompileClasspath,wasmJsTestNpmAggregated,wasmJsTestRuntimeClasspath
71+
io.ktor:ktor-client-mock:3.1.0=allTestSourceSetsCompileDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,desktopTestApiDependenciesMetadata,desktopTestCompileClasspath,desktopTestCompileOnlyDependenciesMetadata,desktopTestImplementationDependenciesMetadata,desktopTestResolvableDependenciesMetadata,desktopTestRuntimeClasspath,wasmJsTestApiDependenciesMetadata,wasmJsTestCompileClasspath,wasmJsTestCompileOnlyDependenciesMetadata,wasmJsTestImplementationDependenciesMetadata,wasmJsTestNpmAggregated,wasmJsTestResolvableDependenciesMetadata,wasmJsTestRuntimeClasspath
6972
io.ktor:ktor-events-jvm:3.1.0=desktopCompileClasspath,desktopRuntimeClasspath,desktopTestCompileClasspath,desktopTestRuntimeClasspath
7073
io.ktor:ktor-events-wasm-js:3.1.0=wasmJsCompileClasspath,wasmJsNpmAggregated,wasmJsRuntimeClasspath,wasmJsTestCompileClasspath,wasmJsTestNpmAggregated,wasmJsTestRuntimeClasspath
7174
io.ktor:ktor-events:3.1.0=allSourceSetsCompileDependenciesMetadata,allTestSourceSetsCompileDependenciesMetadata,commonMainApiDependenciesMetadata,commonMainCompileOnlyDependenciesMetadata,commonMainImplementationDependenciesMetadata,commonMainResolvableDependenciesMetadata,commonTestApiDependenciesMetadata,commonTestCompileOnlyDependenciesMetadata,commonTestImplementationDependenciesMetadata,commonTestResolvableDependenciesMetadata,desktopCompileClasspath,desktopMainApiDependenciesMetadata,desktopMainCompileOnlyDependenciesMetadata,desktopMainImplementationDependenciesMetadata,desktopMainResolvableDependenciesMetadata,desktopRuntimeClasspath,desktopTestApiDependenciesMetadata,desktopTestCompileClasspath,desktopTestCompileOnlyDependenciesMetadata,desktopTestImplementationDependenciesMetadata,desktopTestResolvableDependenciesMetadata,desktopTestRuntimeClasspath,metadataCommonMainCompileClasspath,metadataCompileClasspath,wasmJsCompileClasspath,wasmJsMainApiDependenciesMetadata,wasmJsMainCompileOnlyDependenciesMetadata,wasmJsMainImplementationDependenciesMetadata,wasmJsMainResolvableDependenciesMetadata,wasmJsNpmAggregated,wasmJsRuntimeClasspath,wasmJsTestApiDependenciesMetadata,wasmJsTestCompileClasspath,wasmJsTestCompileOnlyDependenciesMetadata,wasmJsTestImplementationDependenciesMetadata,wasmJsTestNpmAggregated,wasmJsTestResolvableDependenciesMetadata,wasmJsTestRuntimeClasspath
Lines changed: 10 additions & 0 deletions
Loading

solr/ui/src/commonMain/composeResources/values/strings.xml

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,22 @@
1717
-->
1818

1919
<resources>
20-
<!-- Content Descriptions (CD) -->
20+
<!-- Actions (action) -->
21+
<string name="action_connect">Connect</string>
22+
<string name="action_logout">Logout</string>
23+
24+
<!-- Content Descriptions (cd) -->
2125
<string name="cd_solr_logo">Solr Logo</string>
2226

23-
<!-- Navigation (NAV) -->
27+
<!-- Descriptions (desc) -->
28+
<string name="desc_to_get_started">To get started, please provide a Solr host URL:</string>
29+
30+
<!-- Errors (error) -->
31+
<string name="error_invalid_url">The provided URL is invalid.</string>
32+
<string name="error_solr_host_not_found">Solr host could not be found.</string>
33+
<string name="error_unknown">An unknown error occurred.</string>
34+
35+
<!-- Navigation (nav) -->
2436
<string name="nav_cluster">Cluster</string>
2537
<string name="nav_collections">Collections</string>
2638
<string name="nav_configsets">Configsets</string>
@@ -32,15 +44,21 @@
3244
<string name="nav_security">Security</string>
3345
<string name="nav_thread_dump">Thread Dump</string>
3446

47+
<!-- Placeholders (ph) -->
48+
<string name="ph_solr_url">http://127.0.0.1:8983/</string>
49+
50+
<!-- Titles (title) -->
51+
<string name="title_welcome_to_solr">Welcome to Solr Admin UI</string>
52+
3553
<!-- General Text -->
3654
<string name="community">Community</string>
3755
<string name="documentation">Documentation</string>
3856
<string name="irc">IRC</string>
3957
<string name="issue_tracker">Issue Tracker</string>
40-
<string name="logout">Logout</string>
4158
<string name="slack">Slack</string>
4259
<string name="solr_query_syntax">Solr Query Syntax</string>
4360
<string name="support">Support</string>
61+
<string name="connecting">Connecting...</string>
4462

4563
<!-- Uncategorized -->
4664
</resources>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.solr.ui.components.auth
19+
20+
import io.ktor.http.Url
21+
22+
interface UnauthenticatedComponent {
23+
24+
/**
25+
* Aborts the authentication attempt.
26+
*/
27+
fun onAbort()
28+
29+
sealed interface Output {
30+
31+
/**
32+
* Emitted when the user successfully authenticated against
33+
* the Solr instance.
34+
*
35+
* @property url The URL the connection was established with
36+
*/
37+
data class OnConnected(val url: Url): Output
38+
39+
/**
40+
* Emitted when the user aborts the authentication flow.
41+
*/
42+
data object OnAbort: Output
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.apache.solr.ui.components.auth.integration
19+
20+
import com.arkivanov.mvikotlin.core.store.StoreFactory
21+
import io.ktor.client.HttpClient
22+
import org.apache.solr.ui.components.auth.UnauthenticatedComponent
23+
import org.apache.solr.ui.utils.AppComponentContext
24+
25+
class DefaultUnauthenticatedComponent(
26+
componentContext: AppComponentContext,
27+
storeFactory: StoreFactory,
28+
httpClient: HttpClient,
29+
private val output: (UnauthenticatedComponent.Output) -> Unit
30+
) : UnauthenticatedComponent, AppComponentContext by componentContext {
31+
32+
// TODO Implement me
33+
34+
override fun onAbort() = output(UnauthenticatedComponent.Output.OnAbort)
35+
}

solr/ui/src/commonMain/kotlin/org/apache/solr/ui/components/environment/integration/DefaultEnvironmentComponent.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.arkivanov.mvikotlin.core.store.StoreFactory
2222
import com.arkivanov.mvikotlin.extensions.coroutines.stateFlow
2323
import io.ktor.client.HttpClient
2424
import kotlinx.coroutines.ExperimentalCoroutinesApi
25+
import kotlinx.coroutines.SupervisorJob
2526
import org.apache.solr.ui.components.environment.EnvironmentComponent
2627
import org.apache.solr.ui.components.environment.store.EnvironmentStoreProvider
2728
import org.apache.solr.ui.utils.AppComponentContext
@@ -37,13 +38,15 @@ class DefaultEnvironmentComponent(
3738
httpClient: HttpClient,
3839
) : EnvironmentComponent, AppComponentContext by componentContext {
3940

40-
private val mainScope = coroutineScope(mainContext)
41+
private val mainScope = coroutineScope(SupervisorJob() + mainContext)
42+
private val ioScope = coroutineScope(SupervisorJob() + ioContext)
4143

4244
private val store = instanceKeeper.getStore {
4345
EnvironmentStoreProvider(
4446
storeFactory = storeFactory,
4547
client = HttpEnvironmentStoreClient(httpClient),
46-
ioContext = ioContext,
48+
mainContext = mainScope.coroutineContext,
49+
ioContext = ioScope.coroutineContext,
4750
).provide()
4851
}
4952

solr/ui/src/commonMain/kotlin/org/apache/solr/ui/components/environment/store/EnvironmentStoreProvider.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import org.apache.solr.ui.components.environment.store.EnvironmentStore.State
4040
internal class EnvironmentStoreProvider(
4141
private val storeFactory: StoreFactory,
4242
private val client: Client,
43+
private val mainContext: CoroutineContext,
4344
private val ioContext: CoroutineContext,
4445
) {
4546

@@ -58,7 +59,7 @@ internal class EnvironmentStoreProvider(
5859
/**
5960
* Action used for initiating the initial fetch of environment data.
6061
*/
61-
data object FetchInitialSystemData: Action
62+
data object FetchInitialSystemData : Action
6263
}
6364

6465
private sealed interface Message {
@@ -78,9 +79,10 @@ internal class EnvironmentStoreProvider(
7879
data class JavaPropertiesUpdated(val properties: List<JavaProperty>) : Message
7980
}
8081

81-
private inner class ExecutorImpl : CoroutineExecutor<Intent, Action, State, Message, Nothing>() {
82+
private inner class ExecutorImpl :
83+
CoroutineExecutor<Intent, Action, State, Message, Nothing>(mainContext) {
8284

83-
override fun executeAction(action: Action) = when(action) {
85+
override fun executeAction(action: Action) = when (action) {
8486
Action.FetchInitialSystemData -> {
8587
fetchSystemData()
8688
fetchJavaProperties()
@@ -145,6 +147,7 @@ internal class EnvironmentStoreProvider(
145147
system = msg.data.system,
146148
node = msg.data.node,
147149
)
150+
148151
is Message.JavaPropertiesUpdated -> copy(
149152
javaProperties = msg.properties,
150153
)

solr/ui/src/commonMain/kotlin/org/apache/solr/ui/components/root/RootComponent.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ package org.apache.solr.ui.components.root
1919

2020
import com.arkivanov.decompose.router.stack.ChildStack
2121
import com.arkivanov.decompose.value.Value
22+
import org.apache.solr.ui.components.auth.UnauthenticatedComponent
2223
import org.apache.solr.ui.components.main.MainComponent
24+
import org.apache.solr.ui.components.start.StartComponent
2325

2426
/**
2527
* Root component used by each target as an entry point to the application.
@@ -33,9 +35,10 @@ interface RootComponent {
3335

3436
sealed interface Child {
3537

38+
data class Start(val component: StartComponent): Child
39+
3640
data class Main(val component: MainComponent): Child
3741

38-
// TODO Add child once authentication is checked
39-
// data class Unauthenticated(val component: UnauthenticatedComponent): Child
42+
data class Unauthenticated(val component: UnauthenticatedComponent): Child
4043
}
4144
}

0 commit comments

Comments
 (0)