Skip to main content

Show a message to the user

This guide explains how to send a message to the VIKTOR interface to inform/warn users. It will cover aspects as in what scenarios such messages come in handy, what steps to take to achieve this, and examples are given.

Job log

All messages (except for progress messages) are logged in the "Job log", which can be accessed from the editor toolbar:

Interruptive (error) message

New in v13.7.0

UserException is replaced by UserError which supports marking invalid fields in the interface.

Sometimes it is desirable to inform the user about incorrect (or missing) input, and interrupt the job flow so that the user is forced to fix the problem before continuing. For example, when input is not (yet) defined but required at some point within the code, the user does not always know how to fix the problem, while the developer does. We can guide the user in the right direction by providing an error message in the interface, by raising a UserError.

Implementation

  1. Identify at what point in the code an event may occur where the user should be informed and forced to fix
  2. Catch this event (e.g. with if-else statements)
  3. Raise a UserError with the desired message, along with fields that should be marked as invalid
from viktor.errors import UserError, InputViolation


def calculate_block_volume(params):
width = params.width
length = params.length
height = params.height

violations = []
if width is None:
violations.append(InputViolation("Input 'width' cannot be empty!", fields=['width']))
if length is None:
violations.append(InputViolation("Input 'length' cannot be empty!", fields=['length']))
if height is None:
violations.append(InputViolation("Input 'height' cannot be empty!", fields=['height']))

if violations:
raise UserError("Cannot calculate block volume", input_violations=violations)

return width * length * height
tip

For more information on input validation, please see this guide.

Non-interruptive message

New in v14.0.0

UserMessage to show a (non-interruptive) message to the end-user.

Sometimes it is desirable to show a message to the user without interrupting the running app job, such as an informative or warning message. This can be done by using the UserMessage. Three different types of messages can be sent with the UserMessage: a warning, an info and a success message, each of them having a slightly different look within the interface.

Implementation

from viktor import UserMessage

def calculate(params):
if not is_params_recommended(params):
UserMessage.warning("The current set of params is not recommended")

UserMessage.info("The calculation will be run with the following input: ...")

result = run_calculation(...)

UserMessage.success("Analysis successfully finished!")
...

Progress message

Sometimes it is useful to keep the user informed during a long-running job (e.g. processing of analysis, optimization or downloadable content when working with large files or complex calculations), by showing one or more progress messages.

Implementation

from viktor import progress_message

def process_files(my_files):
for file in my_files:
progress_message(message=f'Processing {file}')
... # process file

The progress_message also accepts a percentage. The platform will render the progress with your progress message and a progress bar showing the progress.

def process_files(my_files):
n = len(my_files)
for i, file in enumerate(my_files):
progress_message(message=f'Processing {file}', percentage=(i/n)*100)
... # process file
note
  • Progress messages are only shown to the user during long-running jobs and don't show up during short-running jobs.
  • Progress messages are not logged in the Job log.

Extending a previous message

Whenever a progress message is invoked, the progress window will be "refreshed" with the specified text (i.e. old messages will be dropped). In some cases this is not desired, and new messages should be "appended" to the already existing ones. This can be implemented by using line breaks within the message:

def process_files(my_files):
n = len(my_files)
for i, file in enumerate(my_files):
p_message = f'Reading {file}'
... # read file
progress_message(message=p_message)

p_message += f'\n Processing {file}'
... # process file
progress_message(message=p_message)

p_message += f'\n Export result of {file}'
... # export results
progress_message(message=p_message)