You are viewing PowerRoster™ v8.1. See what's new in Release Note v8.1

Timeline View Configuration

Prev Next

The Timeline View PCF control requires specific App Settings to be configured for proper functionality. These settings are divided into required and optional configurations.

Required Settings

The following settings are mandatory and must be configured for the control to function:

  • Roster/TimelinePCF/Config - Contains the main configuration parameters for the timeline control

  • Roster/TimelinePCF/Datasources - Defines the data sources that the timeline will display

Optional Settings

The following settings provide additional customisation and functionality:

  • Roster/TimelinePCF/FetchXml - Custom FetchXML queries for data retrieval

  • Roster/TimelinePCF/Options - Additional display and behavior options

  • Roster/TimelinePCF/TransformFunction - Custom data transformation logic

Configuration Details

In the following sections, we will explain how to configure each of these settings in detail.

Roster/TimelinePCF/Config

This setting contains the main configuration parameters for the timeline control. The configuration must be a JSON object.

Required Properties

  • render - A function that generates the display content for timeline items

    • Takes item data as input

    • Returns an object with:

    • content - String or HTML element to display

    • className - Optional CSS class name

    • style - Optional inline styles

    • entity - Optional entity information (name, id, formId)

Optional Properties

  • groups - Array of group functions to organize timeline items

    • Each function takes item data and returns group information with:

    • id - Unique group identifier

    • content - Group display name

    • entity - Optional entity information

  • groupOrder - Array of functions to define group ordering

    • Each function compares two groups and returns a number for sorting

  • order - Function to determine item ordering within groups

    • Takes two items and returns a number for sorting

  • name - Optional name for the configuration

  • collapsed - Boolean to set default collapsed state

  • css - Optional CSS string for custom styling

    • These classes can be used in the render function for custom item styles

Default Value Configuration

The following is the default configuration used by the Timeline View control when no custom configuration is provided:

{
  collapsed: false,
  render: (segment) => ({
    entity: {
      name: "vel_rosterpositionallocationsegment",
      id: segment.entityid,
    },
    content:
      "<div><div>" +
      (segment[
        "_vel_resourceid_value@OData.Community.Display.V1.FormattedValue"
      ] ?? "Unallocated") +
      "</div><div>" +
      segment["startdate@OData.Community.Display.V1.FormattedValue"] +
      (segment.maxDate
        ? " - " + new Date(segment.enddate).toLocaleDateString("en-AU")
        : "") +
      "</div></div>",
  }),
  name: "Segments",
  groups: [
    (segment) => {
      if (!segment["_vel_resourceid_value"]) {
        return {
          id: "Unallocated",
          content: "Unallocated",
        };
      }
      return {
        id: segment["_vel_rosterpositionid_value"],
        content:
          segment[
            "_vel_rosterpositionid_value@OData.Community.Display.V1.FormattedValue"
          ],
      };
    },
    (segment) => ({
      id:
        (segment["_vel_resourceid_value"] ?? "") +
        segment["_vel_rosterpositionallocationid_value"],
      content:
        segment[
          "_vel_rosterpositionallocationid_value@OData.Community.Display.V1.FormattedValue"
        ],
    }),
  ],
  groupOrder: [
    (a, b) =>
      a.content === "Unallocated"
        ? 1
        : b.content === "Unallocated"
        ? -1
        : a.content.localeCompare(b.content),
  ],
  css: `
    /* Custom styles for vis.js Timeline by Velrada
    https://visjs.github.io/vis-timeline/docs/timeline/#Styles

    With simulated Fluent UI styling:
    https://developer.microsoft.com/en-us/fluentui#/

    */
    ... more css
  `
}

Default Configuration Breakdown

Render Function - Displays roster positional allocation segments as timeline items - Shows the assigned resource name (or "Unallocated" if no resource is assigned) - Displays the start date and end date of the allocation - Links each item to the vel_rosterpositionallocationsegment entity for navigation

Group Structure The configuration creates a two-level hierarchy:

  1. First Level Groups (Roster Positions): Groups segments by roster position

    • Unallocated segments are grouped under "Unallocated"

    • Allocated segments are grouped by their roster position

  2. Second Level Groups (Position Allocations): Sub-groups segments by specific position allocation

    • Creates unique groups for each resource-position allocation combination

    • Uses the position allocation's display name as the group label

Group Ordering - Places "Unallocated" groups at the top of the list - Orders all other groups alphabetically by their display name - Ensures consistent and predictable group arrangement

Visual Styling - Includes custom CSS that applies Fluent UI design patterns - Integrates with vis.js Timeline component styling - Provides a consistent look and feel with Power Platform applications

This default configuration is specifically designed for roster management scenarios where you need to visualize resource allocations across different positions and time periods.

Roster/TimelinePCF/Datasources

This setting defines the data sources that the timeline will display. The configuration must be a JSON array containing data source objects that follow the DataSource schema.

Data Source Properties

  • id (required) - Unique identifier for the data source

  • fetchXml (optional) - FetchXML query string or App Setting reference to retrieve data

  • params (optional) - Key-value pairs for parameterizing FetchXML queries

    • Special parameters: startDateendDateentityId

    • Parameter references: Use $dataSourceId.propertyName to reference data from other sources

  • entities (optional) - Cached entity data retrieved from the query

  • error (optional) - Error message if data loading fails

  • hidden (optional) - Boolean to hide data source from timeline display

  • preload (optional) - Boolean to load this data source before others (for dependencies)

  • searchKeys (optional) - Array of field names to use for search functionality

Parameter Substitution

FetchXML queries support dynamic parameter substitution:

  • {{entityId}} - Current entity record ID

  • {{startDate}} - Timeline start date

  • {{endDate}} - Timeline end date

  • Custom parameters - Any key from the params object

Data Source References

You can reference data from one source in another using the $ syntax: - $sourceId.propertyName - Gets property values from the referenced data source - Values are formatted as <value>property</value> for FetchXML conditions

Example Configuration

[
  {
    "id": "positions",
    "fetchXml": "Roster/TimelinePCF/PositionsFetch",
    "preload": true,
    "searchKeys": ["vel_name", "vel_code"]
  },
  {
    "id": "allocations",
    "fetchXml": "<fetch><entity name='vel_allocation'><filter><condition attribute='vel_positionid' operator='in'>{{positionIds}}</condition></filter></entity></fetch>",
    "params": {
      "positionIds": "$positions.vel_positionid"
    },
    "searchKeys": ["vel_resourcename"]
  },
  {
    "id": "hidden-reference",
    "fetchXml": "Roster/TimelinePCF/ReferenceFetch",
    "hidden": true,
    "preload": true
  }
]

This configuration creates three data sources: one for positions (preloaded), one for allocations that depends on position data, and one hidden reference source.

Default Value Configuration

[
  {
    id: 'segments',
    fetchXml: 'Roster/TimelinePCF/FetchXml',
    searchKeys: ['PositionName', 'ResourceName']
  },
]

Default Roster/TimelinePCF/FetchXml

The default FetchXML query retrieves roster positional allocation segments with related data for timeline display:

<fetch distinct='true'>
      <entity name='vel_rosterpositionallocationsegment'>
        <attribute name='statecode'/>
        <attribute name='vel_name'/>
        <attribute name='vel_resourceid'/>
        <attribute name='vel_rosterpositionallocationid'/>
        <attribute name='vel_processingstatus'/>
        <attribute name='vel_patternbehaviour'/>
        <attribute name='vel_startdate' alias='startdate'/>
        <attribute name='vel_customday01'/>
        <attribute name='vel_rosterpositionid'/>
        <attribute name='vel_rosterpatternid'/>
        <attribute name='vel_rosterid'/>
        <attribute name='statuscode'/>
        <attribute name='vel_overridemanualassigns'/>
        <attribute name='vel_rosterpositionallocationsegmentid' alias='entityid'/>
        <order attribute='vel_startdate' />
        <filter>
          <condition attribute="statecode" operator="eq" value="0" />
          <condition attribute='vel_rosterid' operator='eq' value='{{entityId}}'/>
        </filter>
        <link-entity name='vel_rosterpositionallocation' from='vel_rosterpositionallocationid' to='vel_rosterpositionallocationid' link-type='inner' alias='allocation'>
          <attribute name='vel_allocationstartdate'/>
          <attribute name='vel_allocationenddate'/>
        </link-entity>
        <link-entity name="vel_rosterposition" from="vel_rosterpositionid" to="vel_rosterpositionid" alias="Position">
            <attribute name="vel_personaid"/>
             <attribute name="vel_name" alias="PositionName" />
        </link-entity>
        <link-entity name="bookableresource" from="bookableresourceid" to="vel_resourceid" alias="Resource">
           <attribute name="name" alias="ResourceName" />
         </link-entity>
      </entity>
    </fetch>

FetchXML Breakdown

Main Entity: vel_rosterpositionallocationsegment - Retrieves the core timeline segments that represent allocation periods - Uses distinct='true' to eliminate duplicate records from joins - Ordered by vel_startdate to ensure chronological display

Key Attributes Retrieved: - vel_startdate (aliased as 'startdate') - Timeline item start time - vel_rosterpositionallocationsegmentid (aliased as 'entityid') - Unique identifier for navigation - vel_resourceid - Links to assigned resource - vel_rosterpositionallocationid - Links to position allocation - vel_rosterpositionid - Links to roster position - Status and processing fields for business logic

Filter Conditions: - statecode = 0 - Only active records - vel_rosterid = {{entityId}} - Segments for the current roster (parameter substitution)

Linked Entities:

  1. vel_rosterpositionallocation (alias: 'allocation')

    • Provides allocation start/end dates

    • Inner join ensures only segments with valid allocations

  2. vel_rosterposition (alias: 'Position')

    • Provides position details and person assignment

    • vel_name aliased as 'PositionName' for display

    • Used in grouping logic

  3. bookableresource (alias: 'Resource')

    • Provides resource information for assigned personnel

    • name aliased as 'ResourceName' for display

    • Used in timeline item rendering and search

Data Flow: 1. Query starts with roster segments for the specified roster 2. Joins allocation data to get timing information 3. Joins position data for grouping and display 4. Joins resource data for personnel assignment display 5. Results ordered chronologically for timeline rendering

This query structure supports the default configuration's grouping (by position and allocation) and rendering (showing resource names and dates) requirements.

Roster/TimelinePCF/Options

This optional setting allows you to customize the behavior and appearance of the vis.js Timeline component used by the Timeline View control. The configuration must be a JSON object containing vis.js Timeline options.

Common Timeline Options

Display Options: - orientation - Controls timeline orientation (e.g., "top""bottom""both") - showCurrentTime - Boolean to display current time indicator - showTooltips - Boolean to enable/disable item tooltips - stack - Boolean to enable item stacking within groups - zoomable - Boolean to enable zoom functionality - moveable - Boolean to enable pan/move functionality

Time Range Options: - start - Timeline start date/time - end - Timeline end date/time - min - Minimum zoom level (earliest date) - max - Maximum zoom level (latest date)

Grouping Options: - groupOrder - Function or string to determine group ordering - groupTemplate - Function to customize group label rendering

Interaction Options: - selectable - Boolean to enable item selection - multiselect - Boolean to enable multiple item selection - editable - Object with editable properties (addupdateTimeupdateGroupremove)

Visual Options: - height - Timeline height (e.g., "400px""100%") - width - Timeline width - margin - Margin configuration object - template - Function to customize item rendering

Example Configuration

{
  "orientation": "top",
  "showCurrentTime": true,
  "zoomable": true,
  "moveable": true,
  "stack": true,
  "height": "500px",
  "start": "2024-01-01",
  "end": "2024-12-31",
  "editable": {
    "add": false,
    "updateTime": true,
    "updateGroup": false,
    "remove": false
  },
  "selectable": true,
  "multiselect": false,
  "showTooltips": true,
  "margin": {
    "item": {
      "horizontal": 10,
      "vertical": 5
    }
  }
}

Default Options

If no options are specified, the Timeline View uses vis.js default settings with minimal customization for Power Platform integration.

For a complete list of available options, refer to the vis.js Timeline documentation.

Roster/TimelinePCF/TransformFunction

This optional setting allows you to define a custom JavaScript function that transforms the raw data from all data sources before it's displayed on the timeline. This is useful for complex data manipulation, filtering, or combining data from multiple sources.

Function Signature

The transform function must follow this signature:

(dataSources: DataSource[]) => any[]
  • Input: Array of DataSource objects containing the loaded entities

  • Output: Array of transformed objects that will be used as timeline items

Function Requirements

  • Must be a valid JavaScript function string

  • Should return an array of objects suitable for timeline display

  • Each returned object should contain properties needed by the render function

  • Function is validated against the TransformFunctionSchema before execution

Data Source Structure

Each data source in the input array contains: - id - Data source identifier - entities - Array of loaded entity records - hidden - Whether the data source is hidden from display - Other data source properties

Use Cases

Data Filtering and Sorting:

(dataSources) => {
  const segments = dataSources.find(ds => ds.id === 'segments')?.entities || [];
  return segments
    .filter(segment => segment.statuscode === 1)
    .sort((a, b) => new Date(a.startdate) - new Date(b.startdate));
}

Combining Multiple Data Sources:

(dataSources) => {
  const segments = dataSources.find(ds => ds.id === 'segments')?.entities || [];
  const allocations = dataSources.find(ds => ds.id === 'allocations')?.entities || [];
  
  return segments.map(segment => ({
    ...segment,
    allocationInfo: allocations.find(alloc => 
      alloc.vel_rosterpositionallocationid === segment._vel_rosterpositionallocationid_value
    )
  }));
}

Data Aggregation:

(dataSources) => {
  const segments = dataSources.find(ds => ds.id === 'segments')?.entities || [];
  
  // Group segments by position and merge overlapping periods
  const grouped = segments.reduce((acc, segment) => {
    const positionId = segment._vel_rosterpositionid_value;
    if (!acc[positionId]) acc[positionId] = [];
    acc[positionId].push(segment);
    return acc;
  }, {});
  
  return Object.values(grouped).flat();
}

Adding Calculated Fields:

(dataSources) => {
  const segments = dataSources.find(ds => ds.id === 'segments')?.entities || [];
  
  return segments.map(segment => ({
    ...segment,
    duration: segment.enddate ? 
      (new Date(segment.enddate) - new Date(segment.startdate)) / (1000 * 60 * 60) : 0,
    isOvertime: segment.vel_customday01 > 8
  }));
}

Default Behavior

When no transform function is provided, the Timeline View: 1. Combines all non-hidden data sources 2. Merges all entity arrays into a single array 3. Passes the combined data directly to the render function

Error Handling

  • Invalid functions will be ignored and logged to the console

  • Runtime errors in the transform function will fall back to default behavior

  • Function validation occurs during control initialization

Performance Considerations

  • Transform functions execute on every data refresh

  • Complex transformations may impact timeline performance

  • Consider data source preload settings for dependent calculations

  • Use efficient algorithms for large datasets

The transform function provides powerful data manipulation capabilities while maintaining the flexibility to work with the existing render and grouping configurations.

Default Transform Function

The Timeline View includes a default transform function that handles segment ordering and end date assignment:

(dataSources) => {
  const orderSegmentsAndAssigEndDate = (segments, paramsEndDate) => {
    segments.sort((a, b) => {
      const startA = new Date(a.startdate);
      const startB = new Date(b.startdate);
      return startA - startB;
    });
    const orderedSegments = segments.map((segment, index) => {
      segment.index = index;
      if (index === segments.length - 1) {
        if (!segment.enddate) {
          const allocationLastRpiDate = segment["allocation.vel_latestrpidate"];
          const allocationEndDate = segment["allocation.vel_allocationenddate"];
          segment.enddate =
            allocationLastRpiDate || allocationEndDate || paramsEndDate;
        }
        return segment;
      }
      const nextSegment = segments[index + 1];
      const enddate = new Date(nextSegment.startdate);
      segment.enddate = enddate.toISOString();
      const splitDate = segment.enddate.split("T")[0].split("-");
      segment["enddate@OData.Community.Display.V1.FormattedValue"] =
        splitDate[2] + "/" + splitDate[1] + "/" + splitDate[0];
      return segment;
    });
    return orderedSegments;
  };
  let endDate;

  const groupedSegments = dataSources.reduce((acc, dataSource) => {
    endDate = dataSource.params?.endDate;
    const segments = dataSource.entities || [];
    segments.forEach((segment) => {
      const allocation =
        segment["_vel_rosterpositionallocationid_value"] || "default";
      if (!acc[allocation]) {
        acc[allocation] = [];
      }
      acc[allocation].push(segment);
    });
    return acc;
  }, {});
  const orderedSegments = Object.entries(groupedSegments).reduce(
    (acc, [, segments]) =>
      acc.concat(orderSegmentsAndAssigEndDate(segments, endDate)),
    []
  );
  return orderedSegments;
}

Default Transform Function Breakdown

Main Purpose: This function processes roster segments to ensure proper timeline display by grouping segments by allocation and calculating missing end dates.

Key Operations:

  1. Data Grouping:

    • Groups segments by roster position allocation ID (_vel_rosterpositionallocationid_value)

    • Creates separate arrays for each allocation to process independently

    • Uses "default" as fallback group for segments without allocation

  2. Chronological Ordering:

    • Sorts segments within each group by start date (startdate)

    • Ensures timeline items display in correct temporal sequence

    • Adds an index property to track segment position

  3. End Date Calculation:

    • For intermediate segments: Uses the next segment's start date as the current segment's end date

    • For final segments: Uses a priority fallback system:

      1. allocation.vel_latestrpidate - Latest RPI (Roster Pattern Instance) date

      2. allocation.vel_allocationenddate - Allocation's official end date

      3. paramsEndDate - Parameter end date from data source

  4. Date Formatting:

    • Converts calculated end dates to ISO string format

    • Creates formatted display values in DD/MM/YYYY format

    • Ensures consistency with Power Platform's OData formatting conventions

Data Flow: 1. Extract entities from all data sources 2. Group segments by allocation ID 3. For each allocation group: - Sort segments chronologically - Calculate missing end dates using next segment's start or fallback values - Format dates for display 4. Flatten all groups back into a single array 5. Return processed segments for timeline rendering

Business Logic: - Handles continuous allocation periods where segments connect end-to-end - Ensures no gaps appear in timeline visualization - Provides intelligent end date inference for incomplete data - Maintains data integrity while enhancing display quality

This default transform function is specifically designed for roster management scenarios where allocation segments need to display as continuous periods without gaps, even when source data doesn't include explicit end dates for all segments.