Skip to content

Функции бизнес-просесса

Вы можете добавлять пользовательские условия/валидаторы/постфукнции для бизнесс-процессов.

Условие

Позволяют скрыть переход.

Внимание

метод WorkflowCondition.execute будет вызываться очень часто, поэтому если у вас очень сложная логика, лучше используйте WorkflowValidator

Для реализации условий реализуйте интерфейс ru.slie.luna.issue.workflow.condition.WorkflowCondition

java
package ru.slie.luna.issue.workflow.condition;

import org.springframework.stereotype.Component;
import ru.slie.luna.exception.ValidateException;
import ru.slie.luna.group.Group;
import ru.slie.luna.group.GroupManager;
import ru.slie.luna.issue.workflow.WorkflowTransientVars;
import ru.slie.luna.issue.workflow.annotations.WorkflowFunctionComponent;
import ru.slie.luna.locale.I18nResolver;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Component
public class UserInGroupCondition implements WorkflowCondition {
    private final I18nResolver i18n;
    private static final String IN_GROUP = "inGroup";
    private final GroupManager groupManager;

    public UserInGroupCondition(I18nResolver i18n,
                                GroupManager groupManager) {
        this.i18n = i18n;
        this.groupManager = groupManager;
    }

    @Override
    public boolean execute(WorkflowTransientVars transientVars, Map<String, String> params) {
        if (transientVars.getUser() == null) {
            return false;
        }
        if (params.containsKey(IN_GROUP) && params.get(IN_GROUP) != null) {
            return transientVars.getUser().getGroups().contains(params.get(IN_GROUP));
        }

        return false;
    }

    @Override
    public String getName() {
        return i18n.getText("app.workflow.condition.user_in_group.label");
    }

    @Override
    public String getDescription() {
        return i18n.getText("app.workflow.condition.user_in_group.description");
    }

    /**
     * Если добавите форму с настройками, этот метод используется для валидации параметров с формы
    */
    @Override
    public void validateParams(Map<String, String> params) throws ValidateException {
        if (params.containsKey(IN_GROUP) && params.get(IN_GROUP) != null) {
            Optional<Group> group = groupManager.getByName(params.get(IN_GROUP));
            if (group.isEmpty()) {
                i18n.getText("app.workflow.condition.user_in_group.group_required");
            }
        } else {
            throw new ValidateException(IN_GROUP, i18n.getText("app.workflow.condition.user_in_group.group_required"));
        }
    }

    /**
     * Можете добавить свой компонент, для отображения в списке функций, иначе будет использоваться название постфукнции
     * Данные с этого метода попадут в ваш кастомный компонент
    */
    @Override
    public Map<String, Object> getParamsForView(Map<String, String> params) {
        Map<String, Object> out = new HashMap<>();
        out.put(IN_GROUP, params.get(IN_GROUP));
        return out;
    }

    /**
     * Можно ли повторно использовать на одном переходе
    */
    @Override
    public boolean isAllowMultiple() {
        return true;
    }
}

Валидатор

Реализация похожа на WorkflowCondition. Разница в том что метод execute должен вызвать ошибку ValidateException. В качестве ключа используйте id поля

java
public class CommentRequiredValidator implements WorkflowValidator {
...
// Для примера можем проверить наличие комментария
@Override
public void execute(WorkflowTransientVars transientVars, Map<String, String> funcParams) throws ValidateException {
    if (transientVars.getRequestParams() == null || !transientVars.getRequestParams().containsKey(IssueFieldConstants.COMMENT)) {
        throw new ValidateException(IssueFieldConstants.COMMENT, "Комментарий обязателен");
    }
}

// Если заранее знаем какие поля обязательны, можем передать это на форму
@Override
public List<String> getRequiredFields(WorkflowTransientVars transientVars, Map<String, String> funcParams) {
    return List.of(IssueFieldConstants.COMMENT);
}
...
}

Постфункция

Если надо что-то выполнить после изменения задачи, используем постфукнции. Все постфункции выполняются в том порядке, в котором они расположены на переходе. Вы можете менять порядок в редакторе бизнес-процесса.

Для создания постфункций, реализуйте интерфейс: WorkflowFunction

Фронтенд

Если вашей функции нудны настройки, создайте vue-компонент:

vue
<script setup lang="ts">
import { PropType } from 'vue'
import { Errors, Option, groupService, SingleSelect } from "luna";

defineProps({
  errors: Object as PropType<Errors>,
})

type Params = {[key: string]: string}

const value = defineModel<Params>();

const groupOptions = async (term: string, excludes: Array<string>) => {
  const {data} = await groupService.findGroups({term}, excludes);
  return data.results.map(g => ({id: g.name, name: g.name} as Option<string>));
}

</script>

<template>
  <div class="form compact user-in-group-condition-component pad">
    <div class="field-group">
      <label for="user-in-group-condition-role">{{ $i18n.t("The current user must be a member of the group") }}</label>
      <SingleSelect :options="groupOptions" v-model="value.inGroup"></SingleSelect>
      <div class="error" v-if="errors['inGroup']">{{ errors['inGroup'] }}</div>
    </div>
  </div>
</template>

<style lang="scss">

</style>
vue
<script setup lang="ts">
import { PropType } from 'vue'
import { WorkflowActionFunction } from "luna";

defineProps({
  func: {
    required: true,
    type: Object as PropType<WorkflowActionFunction>,
  },
  viewParams: {
    required: true,
    type: Object as PropType<{inGroup: string}>,
  }
})

</script>

<template>
  <div class="user-in-group-condition">
    <div>{{ $i18n.t("User in group") }}: {{ viewParams.inGroup }}</div>
  </div>
</template>

Информация

Если вам надо доп информация в компоненте редактирования:

ts
import { inject } from 'vue';
import { Injections } from 'luna';

const action = inject(Injections.workflowAction); // Информация о переходе
const funcType = inject(Injections.workflowFuncType); // Тип функции(условие/валидатор/постфункция)
const actionFunc = inject(Injections.workflowActionFunc); // Информация о текущей функции

Дескриптор

yaml
workflowConditions:
  - key:  UserInGroupCondition
    name: User in group condition
    className: ru.slie.luna.issue.workflow.condition.UserInGroupCondition
    viewComponent:
      path: frontend/UserInGroupEditComponent.js
    editComponent:
      path: frontend/UserInGroupViewComponent.js
workflowValidators:
  - key: CommentRequiredValidator
    name: Comment required validator
    className: ru.slie.luna.issue.workflow.validator.CommentRequiredValidator
workflowPostfunctions:
  - key: MyCustomPostfunction
    name: My custom postfunction
    className: ru.slie.luna.issue.workflow.postfunction.MyCustomPostfunction