Durchsuchbare Dokumentation aufrufen | Zurück zur Dokumentationsübersicht

Navigation: Dokumentationen agorum core > agorum core für Entwickler > agorum core cards


Workflow-Cards

Diese Dokumentation beschreibt, wie Workflow-basierte Cards für die Verwendung auf Mobilgeräten optimiert werden können. Workflows, beispielsweise Freigabe-Workflows, können durch Cards so aufbereitet werden, dass Benutzer direkt über die Objektkarte auf dem Smartphone interagieren können, ohne in die komplexe Workflow-Oberfläche wechseln zu müssen.

Mobile Workflows bzw. Workflow-Schritte

Typisches Szenario

Ein typischer Anwendungsfall für das Bearbeiten eines Workflow-Schritts sind Freigabe-Workflows, etwa für:

Problem: Das verantwortliche Management ist oft unterwegs und muss Dokumente freigeben, hat aber nur ein Smartphone zur Verfügung. Die Standard-Workflow-Oberfläche beinhaltet Bearbeitungsaufgaben, die auf Mobilgeräten nur schwer oder gar nicht durchgeführt werden können.

Lösung: Durch Workflow-Cards können Freigaben direkt über die Objektkarte durchgeführt werden:

  1. Eingang (aktuell) öffnen
  2. Workflow-Aufgabe sehen
  3. Mit einem Klick freigeben, ablehnen oder zurücksenden
  4. Kommentar optional hinzufügen

Wann macht die Optimierung für die mobile Verwendung Sinn?

Die Verwendung von Cards für Workflow-Schritte ist geeignet für:

Die Verwendung von Cards für Workflow-Schritte ist nicht geeignet für:

Hinweis: Cards haben keine Input-Elemente! Für Eingaben werden Message-Popups verwendet.

Workflow-Integration

Die folgenden Schritte erläutern die Integration eines Workflows in eine Card anhand des Freigabeworkflows.

  1. Decorator prüft Workflow und Schritt → entscheidet über Anzeige
  2. Build-Funktion lädt Workflow-Variablen → zeigt Informationen an
  3. Button-Klick → Kommentar-Popup öffnen
  4. Kommentar eingeben → Workflow fortsetzen (workflow.leave())

Schritt 1: Decorator erstellen

Der Decorator entscheidet, wann die Workflow-Card angezeigt wird.

/**
 * Release X-Eyes Decorator
 * Integrates the Release X-Eyes Cardlet in the content area
 */

let decorators = require('/agorum/roi/customers/agorum.cards/js/decorators');
let metadata = require('common/metadata');

/**
 * Decorator function
 * @param {Object} cardlet - The cardlet created by previous decorators
 * @param {Object} object - The object to be displayed
 * @param {Object} def - The cardlet definition with optional parameters
 */
module.exports = (cardlet, object, def) => {
  let data = metadata().load(object, 'sys_acw_processName', 'sys_acw_stepName').data();

  if (data.sys_acw_processName !== 'agorum.workflow.releaseXEyes') return;
  if (data.sys_acw_stepName !== 'uiReleaseStep') return;

  decorators.with(cardlet, 'content', content => {
    // Add the Release X-Eyes Cardlet to content
    content.items = (content.items || []).concat([
      {
        type: 'agorum.workflow.releasexeyes.releaseXEyes',
        id: object.UUID,
      },
    ]);
  });
};

 

Wichtige Metadaten:

Schritt 2: Cardlet erstellen

Das Cardlet definiert die Darstellung und Interaktion.

/**
 * Release X-Eyes Cardlet
 * Displays text fields with labels and three action buttons
 *
 * name: agorum.workflow.releasexeyes.releaseXEyes
 */

let cards = require('/agorum/roi/customers/agorum.cards/js/cards');
let workflow = require('/agorum/roi/customers/agorum.dev/js/lib/workflow');
let message = require('/agorum/roi/customers/agorum.composite/js/lib/message');
let aguila = require('common/aguila');
let i18n = require('common/i18n');

/**
 * Helper function: Removes HTML tags from a string
 */
let stripHtml = html => {
  if (!html) {
    return '';
  }
  return html.replace(/<[^>]*>/g, '').trim();
};

/**
 * Build function: Creates the cardlet structure
 */
let build = (cx, def) => {
  // Store state information in meta object
  cx.meta = {
    tokenId: def.id,
    step: '',
    stepText: '',
    releaseText: '',
    doneBy: '',
  };

  // Load token variables if token ID is available
  if (def.id) {
    try {
      let tokenVariables = workflow.get(def.id);

      // Read and assign workflow variables
      cx.meta.step = tokenVariables.step || '';
      cx.meta.stepText = tokenVariables.stepText || '';
      cx.meta.releaseText = stripHtml(tokenVariables.releaseText || '');
      cx.meta.doneBy = tokenVariables.doneBy; // ? formatDate(tokenVariables.doneBy) : '';

      // Store variables in meta object for later use
      cx.meta.tokenVariables = tokenVariables;
    } catch (error) {
      // Error handling without console.log
    }
  }

  // Create display items
  let displayItems = [
    { label: i18n.translate('agorum.workflow.releasexeyes.label.step'), value: cx.meta.step },
    { label: i18n.translate('agorum.workflow.releasexeyes.label.stepText'), value: cx.meta.stepText },
    { label: i18n.translate('agorum.workflow.releasexeyes.label.releaseText'), html: cx.meta.releaseText },
  ];

  // Add escalation date only if available
  if (cx.meta.doneBy) {
    displayItems.push({
      label: i18n.translate('agorum.workflow.releasexeyes.label.escalationDate'),
      value: cx.meta.doneBy && new Date(cx.meta.doneBy),
      precision: 'minute',
    });
  }

  return {
    type: 'agorum.vertical',
    items: [
      {
        type: 'agorum.display.group',
        labelWidth: 150,
        items: displayItems,
      },
      {
        type: 'agorum.horizontal',
        name: 'actions',
        items: [
          {
            type: 'agorum.button',
            name: 'approve',
            text: i18n.translate('agorum.workflow.releasexeyes.button.approve'),
            color: 'success',
          },
          {
            type: 'agorum.button',
            name: 'reject',
            text: i18n.translate('agorum.workflow.releasexeyes.button.reject'),
            color: 'warning',
          },
          {
            type: 'agorum.vertical',
            flex: 1,
          },
          {
            type: 'agorum.button',
            name: 'backToCreator',
            text: i18n.translate('agorum.workflow.releasexeyes.button.backToCreator'),
            color: 'medium',
          },
        ],
      },
    ],
  };
};

/**
 * Helper function: Shows an input popup
 */
let showCommentPopup = title => {
  return new Promise((resolve, reject) => {
    message
      .popup(title)
      .text(i18n.translate('agorum.workflow.releasexeyes.popup.comment.text'))
      .element({
        type: 'agorum.composite.form.element.text',
        name: 'comment',
        label: i18n.translate('agorum.workflow.releasexeyes.popup.comment.label'),
        textArea: true,
        validation: [
          {
            required: true,
          },
        ],
      })
      .value({ comment: '' })
      .focus('comment')
      .ok()
      .cancel()
      .show((buttonName, value) => {
        if (buttonName === 'ok') {
          resolve(value.comment);
        } else {
          reject('Abgebrochen');
        }
      });
  });
};

/**
 * Event handler: Processes events from the cardlet, only one event show belown
 */
let event = cards.eventHandler();

// Event handler for "Approve" button
event.path('actions', 'approve').on('elementClicked', (cx, param) => {
  // Show input popup
  aguila.enter(() => {
    showCommentPopup(i18n.translate('agorum.workflow.releasexeyes.popup.approve.title'))
      .then(comment => {
        try {
          // Workflow leave with outlet "released" and editorComment variable
          workflow.leave(cx.meta.tokenId, 'released', {
            editorComment: comment,
          });

          // Feedback to user
          message.alert(
            i18n.translate('agorum.workflow.releasexeyes.message.success.title'),
            i18n.translate('agorum.workflow.releasexeyes.message.approve.success')
          );
        } catch (error) {
          message.alert(
            i18n.translate('agorum.workflow.releasexeyes.message.error.title'),
            i18n.translate('agorum.workflow.releasexeyes.message.error.text') + ' ' + error.message
          );
        }
      })
      .catch(error => {
        // Cancelled or error
      });
  });
});

module.exports = { build: build, event: event };

 

Wichtige Konzepte:

Schritt 3: Kommentar-Popup erstellen

Wie im Beispiel zu Schritt 2 gezeigt, wird ein Message-Popup für Benutzereingaben verwendet. Beim Erstellen empfiehlt es sich, die mögliche Verwendung auf mobilen Geräten zu berücksichtigen: 

Schritt 4: Event-Handler implementieren

Event-Handler verarbeiten Button-Klicks und steuern den Workflow, wie im Beispiel zu Schritt 2 gezeigt. 

 

Wichtige Konzepte: