feat: [DASHBOARD] html (#443)

Co-authored-by: Florent Champigny <florent@bere.al>
This commit is contained in:
Florent CHAMPIGNY 2025-12-08 16:13:25 +01:00 committed by GitHub
parent 60b73e6e8d
commit 5a16b94b6f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 172 additions and 1 deletions

View file

@ -0,0 +1,9 @@
package io.github.openflocon.flocon.plugins.dashboard.dsl
import io.github.openflocon.flocon.plugins.dashboard.builder.ContainerBuilder
import io.github.openflocon.flocon.plugins.dashboard.model.config.HtmlConfig
@DashboardDsl
fun ContainerBuilder.html(label: String, value: String) {
add(HtmlConfig(label = label, value = value))
}

View file

@ -0,0 +1,6 @@
package io.github.openflocon.flocon.plugins.dashboard.model.config
data class HtmlConfig(
val label: String,
val value: String,
) : ElementConfig

View file

@ -13,6 +13,7 @@ import io.github.openflocon.flocon.plugins.dashboard.model.config.CheckBoxConfig
import io.github.openflocon.flocon.plugins.dashboard.model.config.ContainerConfig
import io.github.openflocon.flocon.plugins.dashboard.model.config.ElementConfig
import io.github.openflocon.flocon.plugins.dashboard.model.config.FormConfig
import io.github.openflocon.flocon.plugins.dashboard.model.config.HtmlConfig
import io.github.openflocon.flocon.plugins.dashboard.model.config.LabelConfig
import io.github.openflocon.flocon.plugins.dashboard.model.config.MarkdownConfig
import io.github.openflocon.flocon.plugins.dashboard.model.config.PlainTextConfig
@ -94,6 +95,7 @@ private fun parseElementConfig(
is TextConfig -> element.toJson()
is PlainTextConfig -> element.toJson()
is MarkdownConfig -> element.toJson()
is HtmlConfig -> element.toJson()
is TextFieldConfig -> {
val actionId = createActionId(dashboardId, element.id)
@ -249,3 +251,16 @@ internal fun MarkdownConfig.toJson() = buildJsonObject {
put("value", value)
}
}
// {
// "html" : {
// "label": "Formatted Text",
// "value": "<h1>Title</h1>",
// }
// }
internal fun HtmlConfig.toJson() = buildJsonObject {
putJsonObject("html") {
put("label", label)
put("value", value)
}
}

View file

@ -12,6 +12,7 @@ import io.github.openflocon.flocon.myapplication.dashboard.tokens.tokensFlow
import io.github.openflocon.flocon.myapplication.dashboard.user.userFlow
import io.github.openflocon.flocon.plugins.dashboard.dsl.button
import io.github.openflocon.flocon.plugins.dashboard.dsl.checkBox
import io.github.openflocon.flocon.plugins.dashboard.dsl.html
import io.github.openflocon.flocon.plugins.dashboard.dsl.json
import io.github.openflocon.flocon.plugins.dashboard.dsl.label
import io.github.openflocon.flocon.plugins.dashboard.dsl.markdown
@ -20,7 +21,6 @@ import io.github.openflocon.flocon.plugins.dashboard.dsl.text
import io.github.openflocon.flocon.plugins.dashboard.dsl.textField
import io.github.openflocon.flocon.plugins.dashboard.floconDashboard
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@ -182,5 +182,13 @@ fun initializeDashboard(activity: ComponentActivity) {
)
}
}
activity.lifecycleScope.floconDashboard(id = "html") {
section(name = "HTML Section") {
html(
label = "HtmlTitle",
value = "<h1>Title</h1><p>Paragraph with <b>bold</b> text.</p>"
)
}
}
}

View file

@ -10,6 +10,7 @@ import io.github.openflocon.flocon.plugins.dashboard.dsl.json
import io.github.openflocon.flocon.plugins.dashboard.dsl.label
import io.github.openflocon.flocon.plugins.dashboard.dsl.plainText
import io.github.openflocon.flocon.plugins.dashboard.dsl.markdown
import io.github.openflocon.flocon.plugins.dashboard.dsl.html
import io.github.openflocon.flocon.plugins.dashboard.dsl.text
import io.github.openflocon.flocon.plugins.dashboard.dsl.textField
import io.github.openflocon.flocon.plugins.dashboard.floconDashboard
@ -113,6 +114,17 @@ fun initializeDashboard() {
}
}
GlobalScope.launch {
floconDashboard(id = "html") {
section(name = "HTML Test") {
html(
label = "Formatted Text",
value = "<h1>Title</h1><p>Paragraph with <b>bold</b> text.</p>"
)
}
}
}
GlobalScope.launch {
floconDashboard(id = "form") {
form(

View file

@ -63,6 +63,11 @@ internal fun DashboardDomainModel.toUi(): DashboardViewState = DashboardViewStat
label = element.label,
value = element.value,
)
is DashboardElementDomainModel.Html -> DashboardContainerViewState.RowItem.Html(
label = element.label,
value = element.value,
)
}
},
)

View file

@ -58,6 +58,12 @@ data class DashboardContainerViewState(
val label: String,
val value: String,
) : RowItem
@Immutable
data class Html(
val label: String,
val value: String,
) : RowItem
}
/** Any item that can be used to change the value of a field */

View file

@ -24,6 +24,7 @@ import io.github.openflocon.flocondesktop.features.dashboard.model.DashboardCont
import io.github.openflocon.flocondesktop.features.dashboard.model.previewDashboardContainerViewState
import io.github.openflocon.flocondesktop.features.dashboard.view.items.DashboardButtonView
import io.github.openflocon.flocondesktop.features.dashboard.view.items.DashboardCheckBoxView
import io.github.openflocon.flocondesktop.features.dashboard.view.items.DashboardHtmlView
import io.github.openflocon.flocondesktop.features.dashboard.view.items.DashboardLabelView
import io.github.openflocon.flocondesktop.features.dashboard.view.items.DashboardMarkdownView
import io.github.openflocon.flocondesktop.features.dashboard.view.items.DashboardPlainTextView
@ -153,6 +154,13 @@ fun DashboardContainerView(
rowItem = rowItem,
)
}
is DashboardContainerViewState.RowItem.Html -> {
DashboardHtmlView(
modifier = Modifier.fillMaxWidth(),
rowItem = rowItem,
)
}
}
}

View file

@ -0,0 +1,62 @@
package io.github.openflocon.flocondesktop.features.dashboard.view.items
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.awt.SwingPanel
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import io.github.openflocon.flocondesktop.features.dashboard.model.DashboardContainerViewState
import io.github.openflocon.library.designsystem.FloconTheme
import javax.swing.JEditorPane
@Composable
internal fun DashboardHtmlView(
modifier: Modifier = Modifier,
rowItem: DashboardContainerViewState.RowItem.Html,
) {
Column(
modifier = modifier.fillMaxWidth(),
) {
if (rowItem.label.isNotEmpty()) {
Text(
text = rowItem.label,
modifier = Modifier.padding(start = 4.dp, bottom = 4.dp),
color = FloconTheme.colorPalette.onSurface,
style = MaterialTheme.typography.bodyMedium.copy(
fontWeight = FontWeight.Thin,
),
)
}
Box(
modifier = Modifier
.fillMaxWidth()
.background(
color = FloconTheme.colorPalette.secondary,
shape = RoundedCornerShape(8.dp),
)
.padding(8.dp),
) {
SwingPanel(
modifier = Modifier.fillMaxWidth().height(600.dp), // Height needs to be fixed or dynamic
factory = {
JEditorPane().apply {
contentType = "text/html"
isEditable = false
}
},
update = {
it.text = rowItem.value
}
)
}
}
}

View file

@ -96,6 +96,12 @@ internal fun DashboardElementDomainModel.toEntity(
label = label,
value = value,
)
is DashboardElementDomainModel.Html ->
LocalDashboardElement.Html(
label = label,
value = value,
)
}
return DashboardElementEntity(

View file

@ -89,6 +89,12 @@ internal fun DashboardElementEntity.toDomain(json: Json): DashboardElementDomain
label = element.label,
value = element.value,
)
is LocalDashboardElement.Html ->
DashboardElementDomainModel.Html(
label = element.label,
value = element.value,
)
}
} catch (e: Exception) {
e.printStackTrace()

View file

@ -79,4 +79,10 @@ internal sealed interface LocalDashboardElement {
val label: String,
val value: String,
) : LocalDashboardElement
@Serializable
data class Html(
val label: String,
val value: String,
) : LocalDashboardElement
}

View file

@ -7,6 +7,7 @@ import com.flocon.data.remote.dashboard.models.DashboardConfigDataModel
import com.flocon.data.remote.dashboard.models.DashboardContainerDataModel
import com.flocon.data.remote.dashboard.models.DashboardElementDataModel
import com.flocon.data.remote.dashboard.models.FormContainerConfigDataModel
import com.flocon.data.remote.dashboard.models.HtmlConfigDataModel
import com.flocon.data.remote.dashboard.models.LabelConfigDataModel
import com.flocon.data.remote.dashboard.models.MarkdownConfigDataModel
import com.flocon.data.remote.dashboard.models.PlainTextConfigDataModel
@ -55,6 +56,9 @@ fun DashboardElementDataModel.toDomain(): DashboardElementDomainModel? {
markdown?.let {
return it.toDomain()
}
html?.let {
return it.toDomain()
}
return null
}
@ -101,6 +105,11 @@ private fun MarkdownConfigDataModel.toDomain(): DashboardElementDomainModel.Mark
label = label,
)
private fun HtmlConfigDataModel.toDomain(): DashboardElementDomainModel.Html = DashboardElementDomainModel.Html(
value = value,
label = label,
)
private fun ContainerConfigDataModel.toDomain(): ContainerConfigDomainModel = when (this) {
is FormContainerConfigDataModel -> FormContainerConfigDomainModel(
formId = formId,

View file

@ -43,8 +43,16 @@ data class DashboardElementDataModel(
val checkBox: CheckBoxConfigDataModel? = null,
val label: LabelConfigDataModel? = null,
val markdown: MarkdownConfigDataModel? = null,
val html: HtmlConfigDataModel? = null,
)
@Serializable
data class HtmlConfigDataModel(
val label: String,
val value: String,
)
@Serializable
data class MarkdownConfigDataModel(
val label: String,

View file

@ -45,4 +45,9 @@ sealed interface DashboardElementDomainModel {
val label: String,
val value: String,
) : DashboardElementDomainModel
data class Html(
val label: String,
val value: String,
) : DashboardElementDomainModel
}