Skip to content
This repository has been archived by the owner on Apr 12, 2023. It is now read-only.

Commit

Permalink
Add readonly mode (#163)
Browse files Browse the repository at this point in the history
* Add readonly button

* Add global state

* Hide buttons on readonly mode

* Make readonly button more generic

* Fix style for toggle buttons

* Add readonly mode to the list of features

* Fix lint
  • Loading branch information
andrewinci authored Dec 8, 2020
1 parent 2aba669 commit 8d55898
Show file tree
Hide file tree
Showing 12 changed files with 72 additions and 33 deletions.
1 change: 1 addition & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ Download the binary from the latest release for your OS. Learn more [here](https
* Windows, macOS and Linux ready.
* **Dark/Light theme**
* **Auto-update**
* **ReadOnly mode**

## Development

Expand Down
15 changes: 15 additions & 0 deletions app/src/main/kotlin/insulator/helper/GlobalState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package insulator.helper

import javafx.beans.property.SimpleBooleanProperty
import javafx.scene.Node
import tornadofx.visibleWhen

object GlobalState {
val isReadOnlyProperty = SimpleBooleanProperty(true)
}

fun <T : Node> T.hideOnReadonly(): T {
this.visibleWhen { GlobalState.isReadOnlyProperty.not() }
this.managedProperty().bind(GlobalState.isReadOnlyProperty.not())
return this
}
31 changes: 29 additions & 2 deletions app/src/main/kotlin/insulator/ui/component/Button.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,29 @@ package insulator.ui.component
import insulator.helper.dispatch
import insulator.ui.style.ButtonStyle
import insulator.ui.style.theme
import javafx.beans.binding.Bindings
import javafx.beans.property.BooleanProperty
import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.value.ObservableValue
import javafx.event.EventTarget
import javafx.geometry.Pos
import javafx.scene.control.Alert
import javafx.scene.control.Button
import javafx.scene.control.ButtonType
import javafx.scene.paint.Color
import tornadofx.SVGIcon
import tornadofx.action
import tornadofx.addClass
import tornadofx.button
import tornadofx.onChange
import tornadofx.toggleClass

// from https://material.io/resources/icons
const val ICON_MENU_SVG = "M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"
const val ICON_SETTINGS_SVG = "M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"
const val ICON_THEME_SVG = "M20 15.31L23.31 12 20 8.69V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69zM12 18V6c3.31 0 6 2.69 6 6s-2.69 6-6 6z"
const val ICON_LOCK_SVG = "M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"
const val ICON_UNLOCK_SVG = "M12 17c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm6-9h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6h1.9c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm0 12H6V10h12v10z"

fun EventTarget.refreshButton(name: String, refreshOp: suspend () -> Unit) =
button("Refresh") {
Expand All @@ -26,11 +34,30 @@ fun EventTarget.refreshButton(name: String, refreshOp: suspend () -> Unit) =
addClass(ButtonStyle.blueButton)
}

fun EventTarget.readOnlyButton(isReadOnlyProperty: BooleanProperty): Button {
val getIcon = { if (isReadOnlyProperty.value) ICON_LOCK_SVG else ICON_UNLOCK_SVG }
val color = { if (!isReadOnlyProperty.value) Color.RED else theme.mainColor }
val text = { if (isReadOnlyProperty.value) "ReadOnly mode" else "Read/Write mode" }
val button = button {
textProperty().bind(Bindings.createStringBinding(text, isReadOnlyProperty))
action { isReadOnlyProperty.set(isReadOnlyProperty.not().value) }
graphicProperty().bind(
Bindings.createObjectBinding({ SVGIcon(getIcon(), 22.0, color()) }, isReadOnlyProperty)
)
addClass(ButtonStyle.toggleButton)
}
isReadOnlyProperty.onChange {
button.toggleClass(ButtonStyle.alertButton, !isReadOnlyProperty.value)
}
return button
}

fun EventTarget.themeButton(op: () -> Unit) =
button {
text = "Change theme"
action(op)
graphic = SVGIcon(ICON_THEME_SVG, 20.0, theme.mainColor)
addClass(ButtonStyle.burgerButton)
graphic = SVGIcon(ICON_THEME_SVG, 22.0, theme.mainColor)
addClass(ButtonStyle.toggleButton)
}

fun EventTarget.settingsButton(op: () -> Unit) = button {
Expand Down
11 changes: 8 additions & 3 deletions app/src/main/kotlin/insulator/ui/style/ButtonStyle.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import tornadofx.box
import tornadofx.cssclass
import tornadofx.em
import tornadofx.multi
import tornadofx.px

class ButtonStyle : Stylesheet() {
companion object {
val alertButton by cssclass("alert-button")
val blueButton by cssclass("blue-button")
val burgerButton by cssclass("burger-button")
val toggleButton by cssclass("toggle-button")
val settingsButton by cssclass("settings-button")
}

Expand All @@ -38,12 +39,16 @@ class ButtonStyle : Stylesheet() {
backgroundRadius = multi(box(5.em))
backgroundColor = multi(theme.mainColorDark)
}
and(burgerButton) {
textFill = theme.mainColor
and(toggleButton) {
backgroundRadius = multi(box(5.em))
textFill = theme.black
backgroundColor = multi(theme.mainColorDark)
}
}
and(toggleButton) {
textFill = theme.mainColor
minWidth = 200.px
}
and(alertButton) { textFill = theme.alertColor }
and(blueButton) { textFill = theme.blueColor }
}
Expand Down
5 changes: 4 additions & 1 deletion app/src/main/kotlin/insulator/views/main/MainView.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package insulator.views.main

import insulator.di.ClusterScope
import insulator.helper.GlobalState
import insulator.helper.dispatch
import insulator.kafka.model.Cluster
import insulator.ui.ThemeHelper
import insulator.ui.common.InsulatorView
import insulator.ui.component.h1
import insulator.ui.component.h2
import insulator.ui.component.readOnlyButton
import insulator.ui.component.themeButton
import insulator.ui.style.ButtonStyle.Companion.alertButton
import insulator.ui.style.MainViewStyle
Expand Down Expand Up @@ -101,7 +103,8 @@ class MainView @Inject constructor(
menuItem("Schema Registry", ICON_REGISTRY, "sidebar-item-schema-registry") { viewModel.setContentList(ListSchemaView::class, currentWindow) }
menuItem("Consumer Groups", ICON_CONSUMERS, "sidebar-item-consumer-group") { viewModel.setContentList(ListConsumerGroupView::class, currentWindow) }
}
bottom = hbox(alignment = Pos.CENTER) {
bottom = vbox(alignment = Pos.CENTER, spacing = 10) {
readOnlyButton(GlobalState.isReadOnlyProperty)
themeButton { themeHelper.dispatch { changeTheme() } }
}
addClass(MainViewStyle.sidebar)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package insulator.views.main.consumergroup

import insulator.di.ConsumerGroupScope
import insulator.helper.dispatch
import insulator.helper.hideOnReadonly
import insulator.ui.common.InsulatorTabView
import insulator.ui.component.appBar
import insulator.ui.component.confirmationButton
Expand Down Expand Up @@ -59,5 +60,5 @@ class ConsumerGroupView @Inject constructor(override val viewModel: ConsumerGrou
confirmationButton("Delete", "The consumer group \"${viewModel.nameProperty.value}\" will be removed.") {
viewModel.dispatch { delete() }
closeTab()
}
}.hideOnReadonly()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package insulator.views.main.schemaregistry

import insulator.di.ClusterScope
import insulator.helper.dispatch
import insulator.helper.hideOnReadonly
import insulator.ui.common.InsulatorView
import insulator.ui.component.appBar
import insulator.ui.component.refreshButton
Expand Down Expand Up @@ -63,5 +64,5 @@ class ListSchemaView @Inject constructor(
button("Create schema") {
action { viewModel.createNewSchema(currentWindow) }
id = "button-create-schema"
}
}.hideOnReadonly()
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package insulator.views.main.schemaregistry

import insulator.di.SubjectScope
import insulator.helper.hideOnReadonly
import insulator.jsonhelper.JsonFormatter
import insulator.kafka.model.Schema
import insulator.ui.common.InsulatorTabView
Expand Down Expand Up @@ -49,5 +50,5 @@ class SchemaView @Inject constructor(
confirmationButton("Delete", "The schema \"${viewModel.nameProperty.value}\" will be removed.") {
viewModel.delete()
closeTab()
}
}.hideOnReadonly()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package insulator.views.main.topic

import insulator.di.ClusterScope
import insulator.helper.dispatch
import insulator.helper.hideOnReadonly
import insulator.ui.common.InsulatorView
import insulator.ui.component.action
import insulator.ui.component.appBar
Expand Down Expand Up @@ -54,7 +55,7 @@ class ListTopicView @Inject constructor(override val viewModel: ListTopicViewMod
button("Create topic") {
id = "button-create-topic"
action { viewModel.createNewTopic(currentWindow) }
}
}.hideOnReadonly()

override fun onError(throwable: Throwable) {
replaceWith<ListClusterView>()
Expand Down
25 changes: 4 additions & 21 deletions app/src/main/kotlin/insulator/views/main/topic/TopicView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package insulator.views.main.topic

import insulator.di.TopicScope
import insulator.helper.dispatch
import insulator.helper.hideOnReadonly
import insulator.helper.toObservable
import insulator.kafka.consumer.ConsumeFrom
import insulator.kafka.consumer.DeserializationFormat
Expand All @@ -22,25 +23,7 @@ import javafx.scene.control.Control
import javafx.scene.control.SelectionMode
import javafx.scene.control.TableCell
import javafx.scene.layout.Priority
import tornadofx.action
import tornadofx.addClass
import tornadofx.bindSelected
import tornadofx.borderpane
import tornadofx.button
import tornadofx.column
import tornadofx.combobox
import tornadofx.contextmenu
import tornadofx.enableWhen
import tornadofx.hbox
import tornadofx.hgrow
import tornadofx.item
import tornadofx.minus
import tornadofx.onDoubleClick
import tornadofx.stringBinding
import tornadofx.tableview
import tornadofx.text
import tornadofx.vbox
import tornadofx.vgrow
import tornadofx.* // ktlint-disable no-wildcard-imports
import javax.inject.Inject

@TopicScope
Expand Down Expand Up @@ -78,7 +61,7 @@ class TopicView @Inject constructor(
id = "button-produce"
action { viewModel.showProducerView(currentWindow) }
addClass(ButtonStyle.blueButton)
}
}.hideOnReadonly()
}

private fun EventTarget.consumeStopButton() {
Expand Down Expand Up @@ -114,7 +97,7 @@ class TopicView @Inject constructor(
confirmationButton("Delete", "The topic \"${viewModel.nameProperty.value}\" will be removed.") {
viewModel.dispatch { delete() }
closeTab()
}.enableWhen(viewModel.consumerViewModel.isConsumingProperty.not())
}.enableWhen(viewModel.consumerViewModel.isConsumingProperty.not()).hideOnReadonly()

private fun EventTarget.showInfoButton() = button("Info") {
id = "button-info"
Expand Down
1 change: 1 addition & 0 deletions docs/_wiki/Home.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,4 @@ nav_order: 1
* Windows, macOS and Linux ready.
* **Dark/Light theme**
* **Auto-update**
* **ReadOnly mode**
4 changes: 2 additions & 2 deletions docs/_wiki/Producer/Producer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ nav_order: 4
---
# Producer

Insulator supports producing new record to the cluster topics.
Two types of producer are currently supported: Avro and String.
Insulator supports producing new records to the cluster topics.
Two types of producers are currently supported: Avro and String.

The string producer allows the user to create a new record with string key and value.

Expand Down

0 comments on commit 8d55898

Please sign in to comment.