跳转至

Validation rules(验证规则(Validation rules))

Constraints are an inherent part of any scheduling workflow. From simple time restrictions to frequently changing rule matrices, rules can range in complexity. Validation rules allow you to codify these constraints, enabling end users to build and modify schedules with an understanding of the limitations and restrictions that define your organization’s operations.

Each validation rule is backed by a TypeScript function that evaluates whether the current state of a schedule object meets a certain condition as defined in the function logic.

Users are presented with the results of validation rules on the front-end of the Scheduling Gantt Chart widget in Workshop. Upon initial load, all rules are evaluated based on the current state of the Ontology. With each modification to the schedule, the rules are re-evaluated. This process empowers users with the knowledge of how their decisions comply with specific constraints and restrictions.

Below is an example of scheduling constraints within a Scheduling Gantt Chart widget. In the first image, the rule No Operator Overlaps is applied, as indicated with the toggle. This option ensures that only results abiding by this rule will be presented. The following image demonstrates the output. In this example, there is a conflict between the two rows, where the operators, Brad Evans and Ashley Brown, are overlapping.

Example validation rules interface.

Example of non-compliant validation rule.

Orchestration

In the Scheduling Gantt Chart widget in Workshop, the validation rules will be called each time a change is performed to validate the schedules.

1. Action "saveHandler" called on scenario
2. Validation rules called on updated scenario
3. Action "saveHandler" called on scenario
4. Validation rules called on updated scenario
etc ...
n. The user selects "Submit changes", and all Actions that have been applied to the scenario are applied to the Ontology

Example of compliant validation rule.

Implement validation rules

Rules are configured directly in the Scheduling Gantt Chart widget, allowing you to apply rules on a per use case basis. To add a rule to your Scheduling Gantt Chart widget:

  1. Navigate to the schedule data layer for the relevant object type.
  2. Scroll down to the Rules section and select Add new item.
  3. In the Rule Name text box, provide a description of the rule that will be shown to end-users in the Scheduling Gantt Chart.
  4. Select a Constraint Type from the drop down menu. “HARD” will be represented by a red circle with an exclamation point. “SOFT” will be represented by an orange triangle with an exclamation point.
  5. Select the Rule Function from the drop down menu.
  6. Your Function should have a scheduleObjectPrimaryKeys input argument. You can leave this argument empty as it will be autofilled by the widget at runtime.

Example of rule configuration panel in Scheduling Gantt Chart widget.

Functions interface

The types below represent the necessary information to write a validation rule, which includes the status of the rule for each object.

type IFoORule = (scheduleObjectPrimaryKeys: string[]) => Array<IRuleResult>

/*
   Rule result is interpreted as follows:
   true - Rule validated as passing
   false - Rule validated as not passing
   undefined - Rule is not relevant to the given schedule object
*/

interface IRuleResult {
    result: boolean | undefined;
    scheduleObjectPrimaryKey: string;
    details?: Array<IRuleResultDetails>;
}

/*
   By default the text on the pop-over card will display the rule name
   as configured in the rule object

   Optionally, you can explicitly define custom text based on the results
   of rule evaluation

   Additionally, you can provide a set of related puckIds to point users
   towards why a rule is passing or failing
*/

interface IRuleResultDetails {
    description: string;
    relatedPuckIds: string[];
}

Example Functions

The following is a basic example of a Function without the core logic of the validation:

import { Function, Integer } from "@foundry/functions-api";
import { Objects, TaskOrSchedule, ObjectSet} from "@foundry/ontology-api";

// For type definitions, review our public documentation

interface IRuleResultDetails {
    description: string;
    relatedPuckIds: string[];
}
interface IRuleResult {
    result: boolean | undefined;
    scheduleObjectPrimaryKey: string;
    details?: Array<IRuleResultDetails>;
}
type IFoORule = (scheduleObjectPrimaryKeys: string[]) => Array<IRuleResult>


export class MyFunctions {

    // NOTE: it is important that the input argument to a constraint function is named EXACTLY `scheduleObjectPrimaryKeys`.
    // This is how the widget knows to send over the correct set of keys to this Function.
    @Function()
    public async evaluateIfTaskOrScheduleIsValid(scheduleObjectPrimaryKeys: string[]): Promise<Array<IRuleResult>> {
        // Fetch all schedule Ontology Objects
        const taskOrSchedules = await Objects.search().taskOrSchedule()
            .filter(taskOrSchedule => taskOrSchedule.primaryKey.exactMatch(...scheduleObjectPrimaryKeys))
            .allAsync();

        // Iterate through every input key and generate a result entry for it
        const ruleResults: Array<IRuleResult> = scheduleObjectPrimaryKeys.map(pk => {
            const currentTaskOrSchedule = taskOrSchedules.find(taskOrSchedule => taskOrSchedule.primaryKey === pk);
            // Do something with the object and validate something, ...

            // Build the validation result
            const currentValidationDetails: Array<IRuleResultDetails> = [];
            currentValidationDetails.push(
                {
                    description: "This is the description of the validation that passes or not",
                    relatedPuckIds: []
                });

            const currentResult: IRuleResult= {
                result: true,
                scheduleObjectPrimaryKey: pk,
                details: currentValidationDetails,
            };
            return currentResult;
        });

        return ruleResults;
    }
}

More complex validation rules can be created. For example, rules can check the following:

  • If schedules are in sequence (no gap)
  • If the schedules overlap
  • If the person attributed to a schedule has the matching skills or certifications

中文翻译

验证规则(Validation rules)

约束是任何排程工作流中固有的一部分。从简单的时间限制到频繁变化的规则矩阵,规则的复杂程度各不相同。验证规则(Validation rules)允许您将这些约束编码化,使终端用户能够在了解定义组织运营的限制和约束的情况下构建和修改排程。

每个验证规则都由一个TypeScript函数支持,该函数评估排程对象的当前状态是否满足函数逻辑中定义的特定条件。

用户在Workshop的排程甘特图(Scheduling Gantt Chart)组件的前端可以看到验证规则的结果。初始加载时,所有规则都会基于本体论(Ontology)的当前状态进行评估。每次修改排程后,规则都会重新评估。这一过程使用户能够了解其决策如何符合特定的约束和限制。

以下是排程甘特图组件中排程约束的示例。在第一张图片中,无操作员重叠(No Operator Overlaps) 规则已通过切换开关启用。此选项确保只显示符合此规则的结果。下图展示了输出结果。在此示例中,两行之间存在冲突,操作员Brad Evans和Ashley Brown出现了重叠。

验证规则界面示例。

不符合验证规则的示例。

编排(Orchestration)

在Workshop的排程甘特图组件中,每次执行更改时都会调用验证规则来验证排程。

1. 对场景调用"saveHandler"操作
2. 对更新后的场景调用验证规则
3. 对场景调用"saveHandler"操作
4. 对更新后的场景调用验证规则
以此类推...
n. 用户选择"提交更改(Submit changes)",所有已应用于场景的操作都将应用于本体论

符合验证规则的示例。

实现验证规则(Implement validation rules)

规则直接在排程甘特图组件中配置,允许您针对每个用例应用规则。要向排程甘特图组件添加规则:

  1. 导航到相关对象类型的排程数据层。
  2. 向下滚动到规则(Rules)部分,选择添加新项(Add new item)
  3. 规则名称(Rule Name)文本框中,提供将在排程甘特图中向终端用户显示的规则描述。
  4. 从下拉菜单中选择约束类型(Constraint Type)。"硬约束(HARD)"将以带感叹号的红色圆圈表示。"软约束(SOFT)"将以带感叹号的橙色三角形表示。
  5. 从下拉菜单中选择规则函数(Rule Function)
  6. 您的函数应包含一个scheduleObjectPrimaryKeys输入参数。您可以保留此参数为空,因为组件会在运行时自动填充。

排程甘特图组件中的规则配置面板示例。

函数接口(Functions interface)

以下类型表示编写验证规则所需的信息,包括每个对象的规则状态。

type IFoORule = (scheduleObjectPrimaryKeys: string[]) => Array<IRuleResult>

/*
   规则结果解释如下:
   true - 规则验证通过
   false - 规则验证未通过
   undefined - 规则与给定排程对象无关
*/

interface IRuleResult {
    result: boolean | undefined;
    scheduleObjectPrimaryKey: string;
    details?: Array<IRuleResultDetails>;
}

/*
   默认情况下,弹出卡片上的文本将显示规则对象中配置的规则名称

   可选地,您可以根据规则评估结果显式定义自定义文本

   此外,您可以提供一组相关的puckId,以引导用户了解规则通过或失败的原因
*/

interface IRuleResultDetails {
    description: string;
    relatedPuckIds: string[];
}

示例函数(Example Functions)

以下是一个不包含验证核心逻辑的基本函数示例:

import { Function, Integer } from "@foundry/functions-api";
import { Objects, TaskOrSchedule, ObjectSet} from "@foundry/ontology-api";

// 有关类型定义,请查阅我们的公开文档

interface IRuleResultDetails {
    description: string;
    relatedPuckIds: string[];
}
interface IRuleResult {
    result: boolean | undefined;
    scheduleObjectPrimaryKey: string;
    details?: Array<IRuleResultDetails>;
}
type IFoORule = (scheduleObjectPrimaryKeys: string[]) => Array<IRuleResult>


export class MyFunctions {

    // 注意:约束函数的输入参数必须精确命名为`scheduleObjectPrimaryKeys`。
    // 这是组件知道如何将正确的键集发送到此函数的方式。
    @Function()
    public async evaluateIfTaskOrScheduleIsValid(scheduleObjectPrimaryKeys: string[]): Promise<Array<IRuleResult>> {
        // 获取所有排程本体对象
        const taskOrSchedules = await Objects.search().taskOrSchedule()
            .filter(taskOrSchedule => taskOrSchedule.primaryKey.exactMatch(...scheduleObjectPrimaryKeys))
            .allAsync();

        // 遍历每个输入键并为其生成结果条目
        const ruleResults: Array<IRuleResult> = scheduleObjectPrimaryKeys.map(pk => {
            const currentTaskOrSchedule = taskOrSchedules.find(taskOrSchedule => taskOrSchedule.primaryKey === pk);
            // 对对象执行某些操作并验证某些内容...

            // 构建验证结果
            const currentValidationDetails: Array<IRuleResultDetails> = [];
            currentValidationDetails.push(
                {
                    description: "这是验证通过或不通过的描述",
                    relatedPuckIds: []
                });

            const currentResult: IRuleResult= {
                result: true,
                scheduleObjectPrimaryKey: pk,
                details: currentValidationDetails,
            };
            return currentResult;
        });

        return ruleResults;
    }
}

可以创建更复杂的验证规则。例如,规则可以检查以下内容:

  • 排程是否按顺序排列(无间隙)
  • 排程是否重叠
  • 分配给排程的人员是否具备匹配的技能或认证