Templates

Views templates

Viewflow uses a structured approach for template lookup, allowing developers to customize the presentation layer of different workflow views. This approach supports a hierarchy of template customizations, ranging from global overrides to task-specific adjustments. Below, we detail how to customize templates for three primary types of views: Detail View, Start Process View, and Update Process View.

Template Lookup Order

When rendering a view, Viewflow searches for templates in the following order:

  • {opts.app_label}/{opts.app_label}/{flow_task.name}_{self.template_filename}
  • {opts.app_label}/{opts.flow_label}/{self.template_filename}
  • viewflow/workflow/{self.template_filename}

The placeholders used are:

  • {opts.app_label}: The application label.
  • {opts.flow_label}: The label of the flow within the application.
  • {flow_task.name}: The name of the specific task within the flow.
  • {self.template_filename}: The base name of the template file targeted for the view.

Customizing Specific Views

Detail View (task_detail.html)

The Detail View presents detailed information about a specific task within a flow. To customize this view:

  • Task-Specific Customization: Create a template named {app_label}/{app_label}/{task_name}_task_detail.html. For example, to customize the detail view for an approve task in a HelloWorld flow, create: hello_world/hello_world/approve_task_detail.html
  • Flow-Specific Customization: To customize detail views for all tasks within a specific flow, name your template {app_label}/{app_label}/task_detail.html. For example: hello_world/hello_world/task_detail.html
  • Global Customization: For project-wide customizations across all flows, create viewflow/workflow/task_detail.html.

Create Process View (start.html)

The Create Process View is used to initiate a new process. To customize this view, use start.html as self.template_filename. Following the lookup order, you can customize:

  • Flow-Specific Start View: Place your customized start.html in either the flow’s specific directory ({app_label}/{app_label}/start.html) or under the global viewflow/workflow/ directory for a more general override
  • Task-Specific Customization: For task-specific overrides, create a template named {app_label}/{app_label}/{task_name}_task.html.
  • Flow or Global Customization: Similar to the Detail View, place your task.html in the appropriate directory based on the desired level of specificity.

Update Process View (task.html)

The Update Process View is employed when updating an ongoing process. The customization approach is similar, utilizing task.html as self.template_filename:

  • Task-Specific Customization: For task-specific overrides, create a template named {app_label}/{app_label}/{task_name}_task.html.
  • Flow or Global Customization: Similar to the Detail View, place your task.html in the appropriate directory based on the desired level of specificity.

Process data

The process_data.html template is a shared resource within Viewflow, utilized by multiple views to present process-related data. Customizing this template allows for a unified appearance and behavior across different parts of your workflow application. Below are the steps to override the process_data.html template at both the flow-specific and global levels.

Viewflow searches for the process_data.html template using the following order:

  • {app_label}/{flow_label}/process_data.html
  • viewflow/workflow/process_data.html

Template Context Variables

Understanding the context variables available in different templates is crucial for customization:

Context variables available in task_detail.html:

{
    'activation': TaskActivation instance,
    'task': Task model instance,
    'flow_class': The Flow class,
    'flow_task': The specific Node instance,
    'form': Form instance (if applicable)
}

Context variables available in process_detail.html:

{
    'process': Process model instance,
    'flow_class': The Flow class,
    'tasks': QuerySet of Task instances related to the process
}

Context variables available in task_list.html:

{
    'flow_class': The Flow class (optional, may be None for inbox/queue views),
    'task_list': QuerySet of Task instances,
    'filter_form': Task filter form (if filtering is enabled)
}

Context variables available in process_list.html:

{
    'flow_class': The Flow class,
    'process_list': QuerySet of Process instances,
    'filter_form': Process filter form (if filtering is enabled)
}

Creating Custom Template Examples

Here’s an example of a customized task detail template that enhances the default view with additional information:

{# myapp/myapp/approve_task_detail.html #}
{% extends 'viewflow/workflow/task_detail.html' %}

{% block task_details %}
<div class="custom-task-details">
    <div class="task-header">
        <h3>{{ task.flow_task.task_title }}</h3>
        <span class="task-status status-{{ task.status }}">{{ task.get_status_display }}</span>
    </div>

    <div class="task-meta">
        <p><strong>Created:</strong> {{ task.created|date:"F j, Y, H:i" }}</p>
        {% if task.owner %}
        <p><strong>Assigned to:</strong> {{ task.owner.get_full_name|default:task.owner.username }}</p>
        {% endif %}
        {% if task.started %}
        <p><strong>Started:</strong> {{ task.started|date:"F j, Y, H:i" }}</p>
        {% endif %}
    </div>

    <div class="task-actions">
        {% if task|can_execute:request.user %}
        <a href="{% url 'myapp:execute_task' process_pk=task.process_id task_pk=task.pk %}" class="btn btn-primary">
            Process Task
        </a>
        {% endif %}

        {% if task|can_assign:request.user and not task.owner %}
        <a href="{% url 'myapp:assign_task' process_pk=task.process_id task_pk=task.pk %}" class="btn btn-outline">
            Assign to Me
        </a>
        {% endif %}
    </div>
</div>
{% endblock %}

Here’s an example of how to customize the process_data.html template to display business-specific information:

{# myapp/myapp/process_data.html #}
<div class="process-data-container">
    <h3>Process Information</h3>

    <div class="process-field">
        <label>Process ID:</label>
        <span>{{ process.pk }}</span>
    </div>

    <div class="process-field">
        <label>Started:</label>
        <span>{{ process.created|date:"F j, Y, H:i" }}</span>
    </div>

    <div class="process-field">
        <label>Status:</label>
        <span class="status-badge status-{{ process.status }}">{{ process.get_status_display }}</span>
    </div>

    {% if process.finished %}
    <div class="process-field">
        <label>Completed:</label>
        <span>{{ process.finished|date:"F j, Y, H:i" }}</span>
    </div>
    {% endif %}

    {% if process.artifact %}
    <div class="process-field">
        <label>Artifact:</label>
        <div class="artifact-details">
            <span>{{ process.artifact }}</span>
            <a href="{{ process.artifact.get_absolute_url }}" class="view-artifact-link">View Details</a>
        </div>
    </div>
    {% endif %}

    {# Custom fields from your process model #}
    {% if process.approved is not None %}
    <div class="process-field">
        <label>Approval Status:</label>
        <span class="approval-status {% if process.approved %}approved{% else %}rejected{% endif %}">
            {{ process.approved|yesno:"Approved,Rejected" }}
        </span>
    </div>
    {% endif %}

    {% if process.comments %}
    <div class="process-field wide">
        <label>Comments:</label>
        <div class="process-comments">{{ process.comments|linebreaks }}</div>
    </div>
    {% endif %}
</div>

Template Helpers

Viewflow provides several template tags and filters to help with workflow template customization:

{% load viewflow workflow %}

{# Generate URLs for task actions #}
<a href="{% task_action_url task 'assign' %}">Assign</a>
<a href="{% task_action_url task 'execute' %}">Execute</a>
<a href="{% task_action_url task 'unassign' %}">Unassign</a>

{# Generate URLs for process actions #}
<a href="{% process_action_url process 'cancel' %}">Cancel Process</a>
<a href="{% process_action_url process 'detail' %}">View Details</a>

{# Render flow diagram with current task highlighted #}
{% flow_diagram flow_class task=task %}
{# Check if user can perform task actions #}
{% if task|can_execute:request.user %}
    <button type="button">Execute Task</button>
{% endif %}

{% if task|can_assign:request.user %}
    <button type="button">Assign Task</button>
{% endif %}

{# Format task status with appropriate styling #}
<span class="status-badge" style="background-color: {{ task.status|task_status_color }}">
    {{ task.get_status_display }}
</span>

Styling Workflow UI Elements

Add custom CSS styles to enhance the appearance of your workflow interfaces:

/* Task status indicators */
.status-badge {
    display: inline-block;
    padding: 4px 8px;
    border-radius: 4px;
    font-size: 0.8em;
    font-weight: bold;
}

.status-NEW { background-color: #e3f2fd; color: #0d47a1; }
.status-ASSIGNED { background-color: #fff8e1; color: #ff6f00; }
.status-STARTED { background-color: #e8f5e9; color: #2e7d32; }
.status-DONE { background-color: #e0f2f1; color: #00695c; }
.status-CANCELED { background-color: #ffebee; color: #b71c1c; }
.status-ERROR { background-color: #ffebee; color: #b71c1c; }

/* Process data styling */
.process-data-container {
    border: 1px solid #e0e0e0;
    border-radius: 4px;
    padding: 16px;
    background-color: #fafafa;
    margin-bottom: 24px;
}

.process-field {
    display: flex;
    margin-bottom: 8px;
    border-bottom: 1px dotted #e0e0e0;
    padding-bottom: 8px;
}

.process-field label {
    flex: 0 0 150px;
    font-weight: bold;
    color: #424242;
}

.process-field span {
    flex: 1;
}

.process-field.wide {
    flex-direction: column;
}

.process-field.wide label {
    margin-bottom: 8px;
}

/* Task list styling */
.task-list-container .task-item {
    display: flex;
    align-items: center;
    padding: 12px;
    border-bottom: 1px solid #e0e0e0;
    transition: background-color 0.2s;
}

.task-list-container .task-item:hover {
    background-color: #f5f5f5;
}

.task-list-container .task-item .task-title {
    flex: 1;
    font-weight: 500;
}

.task-list-container .task-item .task-meta {
    flex: 0 0 200px;
    color: #757575;
    font-size: 0.9em;
}

.task-list-container .task-item .task-status {
    flex: 0 0 120px;
    text-align: right;
}

Best Practices for Template Customization

When customizing Viewflow templates, consider these best practices:

  1. Extend, Don’t Replace: Whenever possible, extend the base templates rather than replacing them completely to maintain compatibility with future updates.
  2. Use Block Overrides: Identify and override specific blocks in the base templates instead of rewriting entire templates.
  3. Maintain Consistency: Keep a consistent style and layout across all your workflow templates to provide a unified user experience.
  4. Use Template Inheritance: Create a base template for your workflow customizations and extend it for specific views.
  5. Leverage Context Variables: Make full use of the context variables provided by Viewflow to display relevant information.
  6. Test Thoroughly: Test your customized templates with different workflow scenarios to ensure they handle all cases correctly.
  7. Responsive Design: Ensure your templates work well on different screen sizes, especially if your application is accessed on mobile devices.
  8. Accessibility: Maintain accessibility standards in your custom templates by using proper semantic HTML and ARIA attributes where needed.