Skip to content

Commit

Permalink
Improved error handling and reporting for ViurForm
Browse files Browse the repository at this point in the history
  • Loading branch information
phorward committed Dec 15, 2021
1 parent ce934ff commit 7a4b518
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 98 deletions.
1 change: 1 addition & 0 deletions flare/translations/de.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
"flare.network.error.500": "Interner Server Fehler",
"flare.network.hint.401": "\n\nBitte überprüfen Sie, ob Sie angemeldet sind,\nund starten Sie das Programm danach erneut!",
"flare.forms.tooltip": "Hinweis",
"flare.forms.error": "Fehler"
}
1 change: 1 addition & 0 deletions flare/translations/en.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
"flare.network.error.500": "Internal Server Error",
"flare.network.hint.401": "\n\nPlease verify that you're logged in,\nand restart the program.",
"flare.forms.tooltip": "Hint",
"flare.forms.error": "Error"
}
38 changes: 17 additions & 21 deletions flare/viur/bones/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from flare.config import conf
from flare.i18n import translate
from flare.viur.formtooltip import ToolTip
from flare.viur.formerrors import collectBoneErrors, ToolTipError
from flare.viur.formerrors import collectBoneErrors


class ReadFromClientErrorSeverity(IntEnum):
Expand Down Expand Up @@ -485,25 +485,21 @@ def labelWidget(self):
return descrLbl

def tooltipWidget(self):
if (
"params" in self.boneStructure.keys()
and isinstance(self.boneStructure["params"], dict)
and "tooltip" in self.boneStructure["params"].keys()
):
if tooltip := self.boneStructure["params"].get("tooltip"):
return ToolTip(
shortText=self.boneName
if conf["showBoneNames"]
else self.boneStructure.get("descr", self.boneName),
longText=self.boneStructure["params"]["tooltip"],
if conf["showBoneNames"] else self.boneStructure.get("descr", self.boneName),
longText=tooltip,
)
return ""

return None

def errorWidget(self):
if not self.boneErrors:
return False
return ToolTipError(longText=", ".join(self.boneErrors))
tooltip = ToolTip(shortText=translate("flare.forms.error"), longText=", ".join(self.boneErrors))
tooltip.addClass("msg--error", "is-open")
return tooltip

def boneWidget(self, label=True, tooltip=True,*args,**kwargs):
def boneWidget(self, *args, **kwargs):
boneId = "%s___%s" % (self.boneName, str(time.time()).replace(".", "_"))

widget = self.editWidget(errorInformation=self.errors)
Expand All @@ -512,17 +508,13 @@ def boneWidget(self, label=True, tooltip=True,*args,**kwargs):
label = self.labelWidget()
label["for"] = boneId

tooltip = self.tooltipWidget()

error = self.errorWidget()

containerDiv = html5.Div()

containerDiv.addClass(
"flr-bone",
"flr-bone--%s " % self.boneStructure["type"].replace(".", "-"),
"flr-bone--%s" % self.boneName,
)

if self.multiple:
containerDiv.addClass("flr-bone-multiple")
if self.languages:
Expand All @@ -534,10 +526,14 @@ def boneWidget(self, label=True, tooltip=True,*args,**kwargs):
valueDiv = html5.Div()
valueDiv.addClass("flr-value-wrapper")
valueDiv.appendChild(widget)
if tooltip:

if tooltip := self.tooltipWidget():
valueDiv.appendChild(tooltip)

if error:
if error := self.errorWidget():
if not self.boneErrors:
error.hide()

valueDiv.appendChild(error)

containerDiv.appendChild(valueDiv)
Expand Down
33 changes: 0 additions & 33 deletions flare/viur/formerrors.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,36 +29,3 @@ def collectBoneErrors(errorList, currentKey, boneStructure):
boneErrors.append(thisError)

return boneErrors


class ToolTipError(html5.Div):
"""Small utility class for providing tooltips."""

def __init__(self, shortText="", longText="", *args, **kwargs):
super(ToolTipError, self).__init__(*args, **kwargs)
self["class"] = "vi-tooltip msg msg--error is-active is-open"
self.sinkEvent("onClick")

self.prependChild(SvgIcon("icon-arrow-right", title=shortText))

# language=HTMl
self.fromHTML(
"""
<div class="msg-content" [name]="tooltipMsg">
<h2 class="msg-headline" [name]="tooltipHeadline"></h2>
<div class="msg-descr" [name]="tooltipDescr"></div>
</div>
"""
)

self.tooltipHeadline.element.innerHTML = translate("vi.tooltip.error")
self.tooltipDescr.element.innerHTML = longText.replace("\n", "<br />")

def onClick(self, event):
self.toggleClass("is-open")

def _setDisabled(self, disabled):
return

def _getDisabled(self):
return False
76 changes: 49 additions & 27 deletions flare/viur/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,17 +251,19 @@ def actionSuccess(self, req):
self.state.updateState("submitStatus", "finished")

def handleErrors(self):
for error in self.errors:
if error["fieldPath"][0] in self.bones:
boneName = error["fieldPath"][0]
bone_field = self.bones[boneName] # todo dependency errors
boneStructure = self.structure[bone_field.boneName]
if (error["severity"] % 2 == 0 and boneStructure["required"]) or error["severity"] % 2 == 1: # invalid
bone_field.setInvalid()
else:
bone_field.setValid()
at_least_one_silly_error_meeeh = False

for key, form_bone in self.bones.items():
if errors := [error for error in self.errors
if error["fieldPath"][0] == key and
((error["severity"] > 0 and form_bone.bone.required) or error["severity"] % 2 == 1)]:
form_bone.setInvalid(errors)
at_least_one_silly_error_meeeh = True
else:
form_bone.setValid()

self.createFormErrorMessage()
if at_least_one_silly_error_meeeh:
self.createFormErrorMessage()

def createFormSuccessMessage(self):
try:
Expand Down Expand Up @@ -343,7 +345,8 @@ def __init__(self, boneName=None, form=None, defaultvalue=None, hidden=False, fi
self.containerWidget = None
self.labelWidget = None
self.boneWidget = None
self.hasError = None # ??? no plan why this is required
self.errorWidget = None

self.addClass("flr-viur-form-bone")

def onAttach(self):
Expand Down Expand Up @@ -376,10 +379,17 @@ def onAttach(self):
self.structure,
formName=self.form.formName
)
boneFactory = boneClass(self.moduleName, self.boneName, self.structure, self.form.errors)

self.containerWidget, self.labelWidget, self.boneWidget, self.hasError = \
boneFactory = boneClass(
self.moduleName,
self.boneName,
self.structure,
self.form.errors
)

self.containerWidget, self.labelWidget, self.boneWidget, self.errorWidget = \
boneFactory.boneWidget(self.label, filter=self.filter)

self.bone = self.boneWidget.bone

except Exception as e:
Expand Down Expand Up @@ -439,23 +449,35 @@ def _setHide(self, val):
def _setValue(self, val):
self.defaultValue = val

def labelTemplate(self):
return False
"""Default label."""
# language=HTML
return """<label [name]="boneLabel" class="input-group-item--first label flr-label flr-label--{{type}} flr-label--{{boneName}}">{{descr}}</label>"""
def setInvalid(self, errors=None):
self.addClass("is-invalid")
self.removeClass("is-valid")

self.boneWidget.addClass("is-invalid")
self.boneWidget.removeClass("is-valid")

def setInvalid(self):
self.toggleClass("is-invalid", "is-valid") # wrapper
if self.boneLabel:
self.boneLabel.toggleClass("is-invalid", "is-valid") # label
self.boneWidget.toggleClass("is-invalid", "is-valid") # bone
if self.labelWidget:
self.labelWidget.addClass("is-invalid")
self.labelWidget.removeClass("is-valid")

if errors:
self.errorWidget.tooltipDescr.replaceChild("<br>".join([error["errorMessage"] for error in errors]))
self.errorWidget.show()
else:
self.errorWidget.hide()

def setValid(self):
self.toggleClass("is-valid", "is-invalid")
if self.boneLabel:
self.boneLabel.toggleClass("is-valid", "is-invalid")
self.boneWidget.toggleClass("is-valid", "is-invalid")
self.addClass("is-valid")
self.removeClass("is-invalid")

self.boneWidget.addClass("is-valid")
self.boneWidget.removeClass("is-invalid")

if self.labelWidget:
self.labelWidget.addClass("is-valid")
self.labelWidget.removeClass("is-invalid")

self.errorWidget.hide()


@html5.tag("viur-form-submit")
Expand Down
44 changes: 27 additions & 17 deletions flare/viur/formtooltip.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,45 @@
from flare import html5
from flare.i18n import translate
from flare.icons import SvgIcon


class ToolTip(html5.Div):
"""Small utility class for providing tooltips."""

def __init__(self, shortText="", longText="", *args, **kwargs):
super(ToolTip, self).__init__(*args, **kwargs)
self["class"] = "vi-tooltip msg is-active"
self.sinkEvent("onClick")

self.prependChild(SvgIcon("icon-arrow-right", title=shortText))
# fixme: Tooltip should be replaced by Summary-Tag
'''
super(ToolTip, self).__init__(
# language=HTML
"""
<summary class="msg-content" [name]="tooltipMsg">
<flare-svg-icon icon="icon-arrow-right" title="{{shortText}}">
<h2 class="msg-headline" [name]="tooltipHeadline">{{shortText or translate("flare.forms.tooltip")}}</h2>
<details class="msg-descr" [name]="tooltipDescr">{{longText}}</details>
</summary>
""",
shortText=shortText,
longText=longText.replace("\n", "<br />")
)
'''

# language=HTMl
self.fromHTML(
super().__init__(
# language=HTML
"""
<div class="msg-content" [name]="tooltipMsg">
<h2 class="msg-headline" [name]="tooltipHeadline">{{shortText or translate("flare.forms.tooltip")}}</h2>
<div class="msg-descr" [name]="tooltipDescr">{{longText}}</div>
</div>
""",
<flare-svg-icon value="icon-arrow-right" title="{{shortText}}">
<div class="msg-content" [name]="tooltipMsg">
<h2 class="msg-headline" [name]="tooltipHeadline">{{shortText or translate("flare.forms.tooltip")}}</h2>
<div class="msg-descr" [name]="tooltipDescr">{{longText}}</div>
</div>
""",
shortText=shortText,
longText=longText.replace("\n", "<br />")
)

self["class"] = "vi-tooltip msg is-active"
self.sinkEvent("onClick") # this becomes obsolete when tooltip is a summary...

def onClick(self, event):
self.toggleClass("is-open")

def _setDisabled(self, disabled):
# Tooltip cannot be disabled...
return

def _getDisabled(self):
return False

0 comments on commit 7a4b518

Please sign in to comment.