Skip to content

Commit 2286ba9

Browse files
Validate mock response body (#499)
Co-authored-by: Sebastian Neubauer <sebastian.neubauer@exaring.de> Co-authored-by: Florent CHAMPIGNY <champigny.florent@gmail.com>
1 parent 58ae88a commit 2286ba9

2 files changed

Lines changed: 131 additions & 42 deletions

File tree

  • FloconDesktop
    • composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view
    • library/designsystem/src/commonMain/kotlin/io/github/openflocon/library/designsystem/components

FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/mock/edition/view/NetworkEditionWindow.kt

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.RowScope
1212
import androidx.compose.foundation.layout.Spacer
1313
import androidx.compose.foundation.layout.fillMaxSize
1414
import androidx.compose.foundation.layout.fillMaxWidth
15+
import androidx.compose.foundation.layout.height
1516
import androidx.compose.foundation.layout.padding
1617
import androidx.compose.foundation.layout.size
1718
import androidx.compose.foundation.rememberScrollState
@@ -38,6 +39,7 @@ import androidx.compose.ui.text.style.TextAlign
3839
import androidx.compose.ui.unit.DpSize
3940
import androidx.compose.ui.unit.dp
4041
import androidx.compose.ui.util.fastForEach
42+
import com.sebastianneubauer.jsontree.TreeState
4143
import io.github.openflocon.flocondesktop.common.ui.window.FloconWindow
4244
import io.github.openflocon.flocondesktop.common.ui.window.FloconWindowState
4345
import io.github.openflocon.flocondesktop.common.ui.window.createFloconWindowState
@@ -49,11 +51,15 @@ import io.github.openflocon.flocondesktop.features.network.mock.edition.model.He
4951
import io.github.openflocon.flocondesktop.features.network.mock.edition.model.MockNetworkUiModel
5052
import io.github.openflocon.flocondesktop.features.network.mock.edition.model.SelectedMockUiModel
5153
import io.github.openflocon.library.designsystem.FloconTheme
54+
import io.github.openflocon.library.designsystem.components.DefaultLabel
5255
import io.github.openflocon.library.designsystem.components.FloconCheckbox
5356
import io.github.openflocon.library.designsystem.components.FloconDialogButtons
5457
import io.github.openflocon.library.designsystem.components.FloconDialogHeader
58+
import io.github.openflocon.library.designsystem.components.FloconJsonTree
5559
import io.github.openflocon.library.designsystem.components.FloconSurface
60+
import io.github.openflocon.library.designsystem.components.FloconTab
5661
import io.github.openflocon.library.designsystem.components.FloconTextField
62+
import io.github.openflocon.library.designsystem.components.TabType
5763
import io.github.openflocon.library.designsystem.components.defaultLabel
5864
import io.github.openflocon.library.designsystem.components.defaultPlaceHolder
5965

@@ -67,7 +73,7 @@ fun NetworkEditionWindow(
6773
) {
6874
val windowState: FloconWindowState = remember(instanceId) {
6975
createFloconWindowState(
70-
size = DpSize(900.dp, 700.dp)
76+
size = DpSize(900.dp, 800.dp)
7177
)
7278
}
7379
key(windowState, instanceId) {
@@ -202,17 +208,21 @@ fun MockEditorScreen(
202208
)
203209

204210
Row(modifier = Modifier.fillMaxWidth()) {
205-
Tab(
211+
FloconTab(
212+
modifier = Modifier.weight(1F),
206213
text = "HttpCode + Body",
207214
isSelected = mock.responseType == EditableMockNetworkUiModel.ResponseType.BODY,
215+
tabType = TabType.Start,
208216
onSelected = {
209217
mock =
210218
mock.copy(responseType = EditableMockNetworkUiModel.ResponseType.BODY)
211219
}
212220
)
213-
Tab(
221+
FloconTab(
222+
modifier = Modifier.weight(1F),
214223
text = "Exception",
215224
isSelected = mock.responseType == EditableMockNetworkUiModel.ResponseType.EXCEPTION,
225+
tabType = TabType.End,
216226
onSelected = {
217227
mock =
218228
mock.copy(responseType = EditableMockNetworkUiModel.ResponseType.EXCEPTION)
@@ -365,16 +375,66 @@ fun MockEditorScreen(
365375
}
366376
}
367377

368-
FloconTextField(
369-
label = defaultLabel("Body"),
370-
value = bodyResponse.body,
371-
minLines = 4,
372-
onValueChange = { newValue ->
373-
mock = mock.copy(bodyResponse = bodyResponse.copy(body = newValue))
374-
},
375-
modifier = Modifier.fillMaxWidth(),
376-
containerColor = FloconTheme.colorPalette.primary
377-
)
378+
DefaultLabel("Body")
379+
380+
var isEditSelected by remember { mutableStateOf(true) }
381+
382+
Row(modifier = Modifier.fillMaxWidth()) {
383+
FloconTab(
384+
modifier = Modifier.weight(1F),
385+
text = "Edit",
386+
isSelected = isEditSelected,
387+
onSelected = { isEditSelected = true },
388+
tabType = TabType.Start
389+
)
390+
FloconTab(
391+
modifier = Modifier.weight(1F),
392+
text = "Validate",
393+
isSelected = !isEditSelected,
394+
onSelected = { isEditSelected = false },
395+
tabType = TabType.End
396+
)
397+
}
398+
399+
if(isEditSelected) {
400+
FloconTextField(
401+
value = bodyResponse.body,
402+
minLines = 10,
403+
onValueChange = { newValue ->
404+
mock = mock.copy(bodyResponse = bodyResponse.copy(body = newValue))
405+
},
406+
modifier = Modifier.fillMaxWidth(),
407+
containerColor = FloconTheme.colorPalette.primary
408+
)
409+
} else {
410+
var jsonError by remember(bodyResponse.body) { mutableStateOf<Throwable?>(null) }
411+
412+
Box(
413+
modifier = Modifier
414+
.fillMaxWidth()
415+
.height(400.dp)
416+
.background(
417+
color = FloconTheme.colorPalette.primary,
418+
shape = FloconTheme.shapes.medium,
419+
)
420+
.padding(vertical = 4.dp, horizontal = 8.dp),
421+
) {
422+
val throwable = jsonError
423+
if(throwable == null) {
424+
FloconJsonTree(
425+
json = bodyResponse.body,
426+
initialState = TreeState.EXPANDED,
427+
onError = { jsonError = it },
428+
modifier = Modifier.fillMaxSize()
429+
)
430+
} else {
431+
Text(
432+
text = throwable.localizedMessage,
433+
style = FloconTheme.typography.bodySmall
434+
)
435+
}
436+
}
437+
}
378438
}
379439
}
380440
}
@@ -471,32 +531,3 @@ private fun HeaderInputField(
471531
}
472532
}
473533
}
474-
475-
@Composable
476-
fun RowScope.Tab(
477-
text: String,
478-
isSelected: Boolean,
479-
onSelected: () -> Unit
480-
) {
481-
Text(
482-
modifier = Modifier.weight(1f)
483-
.clip(RoundedCornerShape(4.dp))
484-
.background(
485-
color = if (isSelected) {
486-
Color.White.copy(alpha = 0.8f)
487-
} else {
488-
Color.White.copy(alpha = 0.1f)
489-
},
490-
).clickable {
491-
onSelected()
492-
}.padding(vertical = 8.dp),
493-
text = text,
494-
textAlign = TextAlign.Center,
495-
style = FloconTheme.typography.bodyMedium,
496-
color = if (isSelected) {
497-
FloconTheme.colorPalette.primary
498-
} else {
499-
FloconTheme.colorPalette.onSurface.copy(alpha = 0.45f)
500-
},
501-
)
502-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package io.github.openflocon.library.designsystem.components
2+
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.layout.padding
6+
import androidx.compose.foundation.shape.RoundedCornerShape
7+
import androidx.compose.material3.Text
8+
import androidx.compose.runtime.Composable
9+
import androidx.compose.ui.Modifier
10+
import androidx.compose.ui.draw.clip
11+
import androidx.compose.ui.graphics.Color
12+
import androidx.compose.ui.graphics.RectangleShape
13+
import androidx.compose.ui.text.style.TextAlign
14+
import androidx.compose.ui.unit.dp
15+
import io.github.openflocon.library.designsystem.FloconTheme
16+
17+
@Composable
18+
fun FloconTab(
19+
text: String,
20+
isSelected: Boolean,
21+
onSelected: ()-> Unit,
22+
tabType: TabType,
23+
modifier: Modifier = Modifier,
24+
) {
25+
Text(
26+
modifier = modifier
27+
.clip(
28+
when(tabType) {
29+
TabType.Start -> RoundedCornerShape(topStart = 8.dp, bottomStart = 8.dp)
30+
TabType.Middle -> RectangleShape
31+
TabType.End -> RoundedCornerShape(topEnd = 8.dp, bottomEnd = 8.dp)
32+
}
33+
)
34+
.background(
35+
color = if (isSelected) {
36+
Color.White.copy(alpha = 0.8f)
37+
} else {
38+
Color.White.copy(alpha = 0.1f)
39+
},
40+
).clickable {
41+
onSelected()
42+
}.padding(vertical = 8.dp),
43+
text = text,
44+
textAlign = TextAlign.Center,
45+
style = FloconTheme.typography.bodyMedium,
46+
color = if (isSelected) {
47+
FloconTheme.colorPalette.primary
48+
} else {
49+
FloconTheme.colorPalette.onSurface.copy(alpha = 0.45f)
50+
},
51+
)
52+
}
53+
54+
enum class TabType {
55+
Start,
56+
Middle,
57+
End
58+
}

0 commit comments

Comments
 (0)