Wizard: make error messages in ui clickable
#KT-36162 fixed
This commit is contained in:
+4
@@ -47,4 +47,8 @@ abstract class DynamicComponent(private val valuesReadingContext: ValuesReadingC
|
||||
reader(valuesReadingContext)
|
||||
|
||||
open fun onValueUpdated(reference: SettingReference<*, *>?) {}
|
||||
}
|
||||
|
||||
interface FocusableComponent {
|
||||
fun focusOn() {}
|
||||
}
|
||||
+4
@@ -46,4 +46,8 @@ class PathFieldComponent(
|
||||
}
|
||||
|
||||
override fun getUiValue(): Path = Paths.get(uiComponent.text.trim())
|
||||
|
||||
override fun focusOn() {
|
||||
uiComponent.textField.requestFocus()
|
||||
}
|
||||
}
|
||||
+13
-4
@@ -6,11 +6,12 @@
|
||||
package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components
|
||||
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.Setting
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.SettingType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.SettingValidator
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.FocusableComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.panel
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.ErrorAwareComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.ValidationIndicator
|
||||
import java.awt.BorderLayout
|
||||
import javax.swing.JComponent
|
||||
@@ -20,7 +21,7 @@ abstract class UIComponent<V : Any>(
|
||||
labelText: String? = null,
|
||||
private val validator: SettingValidator<V>? = null,
|
||||
private val onValueUpdate: (V) -> Unit = {}
|
||||
) : DynamicComponent(valuesReadingContext) {
|
||||
) : DynamicComponent(valuesReadingContext), ErrorAwareComponent, FocusableComponent {
|
||||
private val validationIndicator = if (validator != null)
|
||||
ValidationIndicator(defaultText = labelText, showText = true)
|
||||
else null
|
||||
@@ -63,6 +64,14 @@ abstract class UIComponent<V : Any>(
|
||||
if (validationIndicator == null) return
|
||||
validationIndicator.validationState = validator.validate(valuesReadingContext, value)
|
||||
}
|
||||
|
||||
override fun focusOn() {
|
||||
uiComponent.requestFocus()
|
||||
}
|
||||
|
||||
override fun findComponentWithError(error: ValidationResult.ValidationError): FocusableComponent? = takeIf {
|
||||
getUiValue()?.let { validator?.validate?.invoke(valuesReadingContext, it)?.isSpecificError(error) } == true
|
||||
}
|
||||
}
|
||||
|
||||
fun <V : Any> UIComponent<V>.valueForSetting(setting: Setting<V, SettingType<V>>): V? =
|
||||
|
||||
+9
@@ -4,6 +4,7 @@ import com.intellij.ui.components.JBTabbedPane
|
||||
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.StringValidators
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.configuratorSettings
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.moduleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ModuleType
|
||||
@@ -11,6 +12,7 @@ import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module.Companion.ALLOWED_SPECIAL_CHARS_IN_MODULE_NAMES
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.ModuleKind
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.FocusableComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.components.TextFieldComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.panel
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingsList
|
||||
@@ -33,6 +35,13 @@ class ModuleSettingsComponent(
|
||||
add("Module Settings", moduleConfiguratorSettingsList.component)
|
||||
}
|
||||
|
||||
fun selectSettingWithError(error: ValidationResult.ValidationError) {
|
||||
val componentWithError = nameField.findComponentWithError(error)
|
||||
?: moduleConfiguratorSettingsList.findComponentWithError(error)?.also { tabPanel.selectedIndex = 1 }
|
||||
?: templateComponent.findComponentWithError(error)?.also { tabPanel.selectedIndex = 0 }
|
||||
componentWithError?.focusOn()
|
||||
}
|
||||
|
||||
private val nameField = TextFieldComponent(
|
||||
valuesReadingContext,
|
||||
labelText = "Name",
|
||||
|
||||
+12
-3
@@ -2,6 +2,7 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.secondStep
|
||||
|
||||
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset
|
||||
@@ -17,7 +18,9 @@ class SecondStepWizardComponent(
|
||||
uiEditorUsagesStats: UiEditorUsageStats
|
||||
) : WizardStepComponent(wizard.valuesReadingContext) {
|
||||
private val moduleEditorSubStep =
|
||||
ModulesEditorSubStep(wizard.valuesReadingContext, uiEditorUsagesStats, ::onNodeSelected).asSubComponent()
|
||||
ModulesEditorSubStep(wizard.valuesReadingContext, uiEditorUsagesStats, ::onNodeSelected) {
|
||||
templatesSubStep.selectSettingWithError(it)
|
||||
}.asSubComponent()
|
||||
private val templatesSubStep = ModuleSettingsSubStep(wizard, uiEditorUsagesStats).asSubComponent()
|
||||
|
||||
override val component = splitterFor(
|
||||
@@ -34,12 +37,14 @@ class SecondStepWizardComponent(
|
||||
class ModulesEditorSubStep(
|
||||
valuesReadingContext: ValuesReadingContext,
|
||||
uiEditorUsagesStats: UiEditorUsageStats,
|
||||
onNodeSelected: (data: DisplayableSettingItem?) -> Unit
|
||||
onNodeSelected: (data: DisplayableSettingItem?) -> Unit,
|
||||
selectSettingWithError: (ValidationResult.ValidationError) -> Unit
|
||||
) : SubStep(valuesReadingContext) {
|
||||
private val moduleSettingComponent = ModulesEditorComponent(
|
||||
valuesReadingContext,
|
||||
uiEditorUsagesStats,
|
||||
onNodeSelected
|
||||
onNodeSelected,
|
||||
selectSettingWithError
|
||||
).asSubComponent()
|
||||
|
||||
override fun buildContent(): JComponent = panel {
|
||||
@@ -74,6 +79,10 @@ class ModuleSettingsSubStep(
|
||||
changeComponent()
|
||||
}
|
||||
|
||||
fun selectSettingWithError(error: ValidationResult.ValidationError) {
|
||||
moduleSettingsComponent.selectSettingWithError(error)
|
||||
}
|
||||
|
||||
private fun changeComponent() {
|
||||
panel.removeAll()
|
||||
val component = when (selectedNode) {
|
||||
|
||||
+12
-2
@@ -10,6 +10,7 @@ import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons
|
||||
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.moduleConfigurators.moduleType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.templates.TemplatesPlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
@@ -17,6 +18,8 @@ import org.jetbrains.kotlin.tools.projectWizard.templates.Template
|
||||
import org.jetbrains.kotlin.tools.projectWizard.templates.settings
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.Component
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.ErrorAwareComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting.SettingsList
|
||||
import java.awt.*
|
||||
import javax.swing.JComponent
|
||||
@@ -25,7 +28,7 @@ import javax.swing.JPanel
|
||||
class TemplatesComponent(
|
||||
valuesReadingContext: ValuesReadingContext,
|
||||
uiEditorUsagesStats: UiEditorUsageStats
|
||||
) : DynamicComponent(valuesReadingContext) {
|
||||
) : DynamicComponent(valuesReadingContext), ErrorAwareComponent {
|
||||
private val chooseTemplateComponent: ChooseTemplateComponent =
|
||||
ChooseTemplateComponent(valuesReadingContext) { template ->
|
||||
uiEditorUsagesStats.moduleTemplatesSet++
|
||||
@@ -49,6 +52,9 @@ class TemplatesComponent(
|
||||
}
|
||||
}
|
||||
|
||||
override fun findComponentWithError(error: ValidationResult.ValidationError): SettingComponent<*, *>? =
|
||||
templateSettingsComponent.findComponentWithError(error)
|
||||
|
||||
private fun switchState(selectedTemplate: Template?) {
|
||||
panel.removeAll()
|
||||
when (selectedTemplate) {
|
||||
@@ -243,7 +249,7 @@ class TemplateDescriptionComponent(
|
||||
private class TemplateSettingsComponent(
|
||||
valuesReadingContext: ValuesReadingContext,
|
||||
removeTemplate: () -> Unit
|
||||
) : DynamicComponent(valuesReadingContext) {
|
||||
) : DynamicComponent(valuesReadingContext), ErrorAwareComponent {
|
||||
private val templateDescriptionComponent = TemplateDescriptionComponent(
|
||||
needRemoveButton = true,
|
||||
nonDefaultBackgroundColor = UIUtil.getEditorPaneBackground(),
|
||||
@@ -256,6 +262,10 @@ private class TemplateSettingsComponent(
|
||||
component.bordered()
|
||||
}
|
||||
|
||||
override fun findComponentWithError(error: ValidationResult.ValidationError): SettingComponent<*, *>? =
|
||||
settings.findComponentWithError(error)
|
||||
|
||||
|
||||
fun setTemplate(module: Module, selectedTemplate: Template) {
|
||||
settings.setSettings(selectedTemplate.settings(module))
|
||||
templateDescriptionComponent.updateSelectedTemplate(selectedTemplate)
|
||||
|
||||
+8
-2
@@ -4,6 +4,7 @@ import com.intellij.ui.JBColor
|
||||
import org.jetbrains.kotlin.idea.projectWizard.UiEditorUsageStats
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ListSettingType
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.reference
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.KotlinPlugin
|
||||
import org.jetbrains.kotlin.tools.projectWizard.plugins.kotlin.ProjectKind
|
||||
@@ -20,7 +21,8 @@ import javax.swing.JComponent
|
||||
class ModulesEditorComponent(
|
||||
valuesReadingContext: ValuesReadingContext,
|
||||
uiEditorUsagesStats: UiEditorUsageStats,
|
||||
oneEntrySelected: (data: DisplayableSettingItem?) -> Unit
|
||||
oneEntrySelected: (data: DisplayableSettingItem?) -> Unit,
|
||||
selectSettingWithError: (ValidationResult.ValidationError) -> Unit
|
||||
) : SettingComponent<List<Module>, ListSettingType<Module>>(KotlinPlugin::modules.reference, valuesReadingContext) {
|
||||
private val tree: ModulesEditorTree =
|
||||
ModulesEditorTree(
|
||||
@@ -64,7 +66,11 @@ class ModulesEditorComponent(
|
||||
}
|
||||
}
|
||||
|
||||
override val validationIndicator = ValidationIndicator(showText = true).apply {
|
||||
override val validationIndicator = ValidationIndicator(showText = true) { error ->
|
||||
val module = error.target as? Module ?: return@ValidationIndicator
|
||||
tree.selectModule(module)
|
||||
selectSettingWithError(error)
|
||||
}.apply {
|
||||
background = tree.background
|
||||
}
|
||||
}
|
||||
|
||||
+13
@@ -7,12 +7,14 @@ import com.intellij.ui.treeStructure.Tree
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.DisplayableSettingItem
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Module
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.Sourceset
|
||||
import org.jetbrains.kotlin.tools.projectWizard.settings.buildsystem.path
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.icon
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JTree
|
||||
import javax.swing.tree.DefaultMutableTreeNode
|
||||
import javax.swing.tree.DefaultTreeModel
|
||||
import javax.swing.tree.TreePath
|
||||
import javax.swing.tree.TreeSelectionModel
|
||||
|
||||
class ModulesEditorTree(
|
||||
@@ -32,6 +34,17 @@ class ModulesEditorTree(
|
||||
openPaths.forEach(::expandPath)
|
||||
}
|
||||
|
||||
fun selectModule(moduleToSelect: Module) {
|
||||
for (value in (model.root as DefaultMutableTreeNode).depthFirstEnumeration().iterator()) {
|
||||
val node = value as? DefaultMutableTreeNode ?: continue
|
||||
val module = node.userObject as? Module ?: continue
|
||||
if (module.path == moduleToSelect.path) {
|
||||
selectionPath = TreePath(node.path)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val selectedSettingItem
|
||||
get() = selectedNode?.userObject?.safeAs<DisplayableSettingItem>()
|
||||
|
||||
|
||||
+2
-1
@@ -4,11 +4,12 @@ import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.*
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.Displayable
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.FocusableComponent
|
||||
|
||||
abstract class SettingComponent<V : Any, T: SettingType<V>>(
|
||||
val reference: SettingReference<V, T>,
|
||||
val valuesReadingContext: ValuesReadingContext
|
||||
) : DynamicComponent(valuesReadingContext), Displayable {
|
||||
) : DynamicComponent(valuesReadingContext), Displayable, FocusableComponent {
|
||||
var value: V?
|
||||
get() = reference.value
|
||||
set(value) {
|
||||
|
||||
+17
-3
@@ -3,18 +3,25 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting
|
||||
import com.intellij.ui.components.panels.VerticalLayout
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.ValuesReadingContext
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.SettingReference
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.Component
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.isSpecificError
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.DynamicComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.FocusableComponent
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.PanelWithStatusText
|
||||
import javax.swing.JComponent
|
||||
|
||||
interface ErrorAwareComponent {
|
||||
fun findComponentWithError(error: ValidationResult.ValidationError): FocusableComponent?
|
||||
}
|
||||
|
||||
class SettingsList(
|
||||
settings: List<SettingReference<*, *>>,
|
||||
private val valuesReadingContext: ValuesReadingContext
|
||||
) : DynamicComponent(valuesReadingContext) {
|
||||
) : DynamicComponent(valuesReadingContext), ErrorAwareComponent {
|
||||
private val panel = PanelWithStatusText(VerticalLayout(5), "This module has no settings to configure")
|
||||
|
||||
private var settingComponents: List<Component> = emptyList()
|
||||
var settingComponents: List<SettingComponent<*, *>> = emptyList()
|
||||
private set
|
||||
|
||||
init {
|
||||
setSettings(settings)
|
||||
@@ -35,4 +42,11 @@ class SettingsList(
|
||||
}
|
||||
settingComponents.forEach { setting -> setting.onInit(); panel.add(setting.component) }
|
||||
}
|
||||
|
||||
override fun findComponentWithError(error: ValidationResult.ValidationError) =
|
||||
settingComponents.firstOrNull { component ->
|
||||
val value = component.value ?: return@firstOrNull false
|
||||
val result = component.setting.validator.validate(valuesReadingContext, value)
|
||||
result isSpecificError error
|
||||
}
|
||||
}
|
||||
+4
@@ -29,5 +29,9 @@ abstract class UIComponentDelegatingSettingComponent<V : Any, T : SettingType<V>
|
||||
value?.let(uiComponent::updateUiValue)
|
||||
}
|
||||
|
||||
override fun focusOn() {
|
||||
uiComponent.focusOn()
|
||||
}
|
||||
|
||||
override val component: JComponent by lazy(LazyThreadSafetyMode.NONE) { uiComponent.component }
|
||||
}
|
||||
+29
-3
@@ -2,28 +2,49 @@ package org.jetbrains.kotlin.tools.projectWizard.wizard.ui.setting
|
||||
|
||||
import com.intellij.icons.AllIcons
|
||||
import com.intellij.ui.JBColor
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import com.intellij.util.ui.EmptyIcon
|
||||
import org.jetbrains.kotlin.tools.projectWizard.core.entity.ValidationResult
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.asHtml
|
||||
import org.jetbrains.kotlin.tools.projectWizard.wizard.ui.label
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Cursor
|
||||
import java.awt.event.MouseEvent
|
||||
import java.awt.event.MouseListener
|
||||
import javax.swing.BorderFactory
|
||||
import javax.swing.Icon
|
||||
import javax.swing.JPanel
|
||||
|
||||
class ValidationIndicator(
|
||||
defaultText: String? = null,
|
||||
private val showText: Boolean
|
||||
private val showText: Boolean,
|
||||
private val onClickAction: ((ValidationResult.ValidationError) -> Unit)? = null
|
||||
) : JPanel(BorderLayout()) {
|
||||
private val textLabel = defaultText?.let { label("$it: ") }
|
||||
private val errorLabel = label(" ").apply {
|
||||
foreground = JBColor.red
|
||||
}
|
||||
|
||||
private var currentError: ValidationResult.ValidationError? = null
|
||||
|
||||
|
||||
init {
|
||||
border = BorderFactory.createEmptyBorder(3, 3, 3, 3)
|
||||
textLabel?.let { add(it, BorderLayout.WEST) }
|
||||
add(errorLabel, BorderLayout.CENTER)
|
||||
|
||||
if (onClickAction != null) {
|
||||
cursor = Cursor(Cursor.HAND_CURSOR)
|
||||
addMouseListener(object : MouseListener {
|
||||
override fun mouseReleased(p0: MouseEvent?) {}
|
||||
override fun mouseEntered(p0: MouseEvent?) {}
|
||||
override fun mouseExited(p0: MouseEvent?) {}
|
||||
override fun mousePressed(p0: MouseEvent?) {}
|
||||
|
||||
override fun mouseClicked(p0: MouseEvent?) {
|
||||
currentError?.let(onClickAction)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun setIcon(icon: Icon?) {
|
||||
@@ -31,6 +52,9 @@ class ValidationIndicator(
|
||||
else errorLabel.icon = icon ?: EmptyIcon.ICON_16
|
||||
}
|
||||
|
||||
private fun String.linkifyErrorText() =
|
||||
if (onClickAction == null) this
|
||||
else "<u>$this</u>".asHtml()
|
||||
|
||||
var validationState: ValidationResult = ValidationResult.OK
|
||||
set(value) {
|
||||
@@ -40,12 +64,14 @@ class ValidationIndicator(
|
||||
setIcon(null)
|
||||
errorLabel.text = " "
|
||||
toolTipText = null
|
||||
currentError = null
|
||||
}
|
||||
is ValidationResult.ValidationError -> {
|
||||
setIcon(AllIcons.General.Error)
|
||||
val errors = value.messages.firstOrNull().orEmpty()
|
||||
toolTipText = errors
|
||||
if (showText) errorLabel.text = errors
|
||||
if (showText) errorLabel.text = errors.linkifyErrorText()
|
||||
currentError = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -354,7 +354,7 @@ class ListSettingType<V : Any>(private val parser: Parser<V>) : SettingType<List
|
||||
validate { values ->
|
||||
values.fold(ValidationResult.OK as ValidationResult) { result, value ->
|
||||
result and when (value) {
|
||||
is Validatable<*> -> (value.validator as SettingValidator<Any>).validate(this, value)
|
||||
is Validatable<*> -> (value.validator as SettingValidator<Any>).validate(this, value).withTargetIfNull(value)
|
||||
else -> ValidationResult.OK
|
||||
}
|
||||
}
|
||||
|
||||
+16
-3
@@ -55,8 +55,8 @@ sealed class ValidationResult {
|
||||
override val isOk = true
|
||||
}
|
||||
|
||||
class ValidationError(val messages: List<String>) : ValidationResult() {
|
||||
constructor(message: String) : this(listOf(message))
|
||||
data class ValidationError(val messages: List<String>, val target: Any? = null) : ValidationResult() {
|
||||
constructor(message: String, target: Any? = null) : this(listOf(message), target)
|
||||
|
||||
override val isOk = false
|
||||
}
|
||||
@@ -73,6 +73,19 @@ sealed class ValidationResult {
|
||||
}
|
||||
}
|
||||
|
||||
infix fun ValidationResult.isSpecificError(error: ValidationResult.ValidationError) =
|
||||
this is ValidationResult.ValidationError && messages.firstOrNull() == error.messages.firstOrNull()
|
||||
|
||||
fun ValidationResult.withTarget(target: Any) = when (this) {
|
||||
ValidationResult.OK -> this
|
||||
is ValidationResult.ValidationError -> copy(target = target)
|
||||
}
|
||||
|
||||
fun ValidationResult.withTargetIfNull(target: Any) = when (this) {
|
||||
ValidationResult.OK -> this
|
||||
is ValidationResult.ValidationError -> if (this.target == null) copy(target = target) else this
|
||||
}
|
||||
|
||||
fun ValidationResult.toResult() = when (this) {
|
||||
ValidationResult.OK -> UNIT_SUCCESS
|
||||
is ValidationResult.ValidationError -> Failure(messages.map { ValidationError(it) })
|
||||
@@ -85,7 +98,7 @@ interface Validatable<out V> {
|
||||
|
||||
fun <V, Q : Validatable<Q>> ValuesReadingContext.validateList(list: List<Q>) = settingValidator<V> {
|
||||
list.fold(ValidationResult.OK as ValidationResult) { result, value ->
|
||||
result and value.validator.validate(this, value)
|
||||
result and value.validator.validate(this, value).withTarget(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user