Skip to content
DataMiner DoJo

More results...

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
Search in posts
Search in pages
Search in posts
Search in pages
Log in
Menu
  • Updates & Insights
  • Questions
  • Learning
    • E-learning Courses
    • Empower Replay: Limited Edition
    • Tutorials
    • Open Classroom Training
    • Certification
      • DataMiner Fundamentals
      • DataMiner Configurator
      • DataMiner Automation
      • Scripts & Connectors Developer: HTTP Basics
      • Scripts & Connectors Developer: SNMP Basics
      • Visual Overview – Level 1
      • Verify a certificate
    • Video Library
    • Books We Like
    • >> Go to DataMiner Docs
  • Expert Center
    • Solutions & Use Cases
      • Solutions
      • Use Case Library
    • Markets & Industries
      • Media production
      • Government & defense
      • Content distribution
      • Service providers
      • Partners
      • OSS/BSS
    • Agile
      • Agile Webspace
      • Everything Agile
        • The Agile Manifesto
        • Best Practices
        • Retro Recipes
      • Methodologies
        • The Scrum Framework
        • Kanban
        • Extreme Programming
      • Roles
        • The Product Owner
        • The Agile Coach
        • The Quality & UX Coach (QX)
    • DataMiner DevOps Professional Program
      • About the DevOps Program
      • DataMiner DevOps Support
  • Downloads
  • More
    • DataMiner Releases & Updates
    • Feature Suggestions
    • Climb the leaderboard!
    • Swag Shop
    • Contact
    • Global Feedback Survey
  • PARTNERS
    • All Partners
    • Technology Partners
    • Strategic Partner Program
    • Deal Registration
  • >> Go to dataminer.services

Only show availble resources for ResourceFieldDescriptor

Solved1.15K views14th April 2023DOM SRM resources
2
Gerwin van der Kamp [DevOps Enabler]2.92K 14th April 2023 0 Comments

Hi,

I'm experimenting with the ResourceFieldDescriptor, and i was wondering if there is a way to only show the available resources in that list for a certain time range?

Gerwin van der Kamp [DevOps Enabler] Selected answer as best 14th April 2023

3 Answers

  • Active
  • Voted
  • Newest
  • Oldest
2
Martijn Vanallemeersch [SLC] [DevOps Member]953 Posted 14th April 2023 0 Comments

This button is part of the DOM definition as I only want to see this button in certain DOM states & in the script which is triggered from the DOM button I immediately know the id of the DOM where I want to store the selected resources again from my interactive automation (would work with a low code app button as well but is a bit less intuitive)

Do note that you need to set the DOM action to interactive before this is possible

https://docs.dataminer.services/user-guide/Advanced_Modules/DOM/DOM_actions.html

This is also possible to set with the DOM editor script on actions

This is some example code from Empower to select some available resources from a certain resource pool & store them back in DOM

<?xml version="1.0" encoding="utf-8" ?>
<DMSScript options="272" xmlns="http://www.skyline.be/automation">
<Name>ServiceOrderApp_SelectAvailableResources</Name>
<Description />
<Type>Automation</Type>
<Author>SKYLINE2\ThomasGH</Author>
<CheckSets>FALSE</CheckSets>
<Folder>DOM_ServiceOrderApp</Folder>

<Protocols>
</Protocols>

<Memory>
</Memory>

<Parameters>
</Parameters>

<Script>
<Exe id="1" type="csharp">
<Value>
<![CDATA[using Skyline.DataMiner.Automation;
using Skyline.DataMiner.Net.Apps.DataMinerObjectModel;
using Skyline.DataMiner.Net.Apps.DataMinerObjectModel.Actions;
using Skyline.DataMiner.Net.Apps.Sections.Sections;
using Skyline.DataMiner.Net.Messages;
using Skyline.DataMiner.Net.Messages.SLDataGateway;
using Skyline.DataMiner.Net.ResourceManager.Objects;
using Skyline.DataMiner.Net.Sections;
using System;
using System.Collections.Generic;
using System.Linq;
using Skyline.DataMiner.DataMinerSolutions.ProcessAutomation.MessageHandler;
using Skyline.DataMiner.DataMinerSolutions.ProcessAutomation.Common.Objects.Exceptions;

namespace DataMiner_Empower_DOM_2023.ServiceOrderApp_SelectAvailableResources
{
public class Script
{
private const string PoolName = "Server Capacity";
private const string ModuleId = "process_automation";
private const string StartTimeFieldName = "Start time";
private const string EndTimeFieldName = "End time";
private const string SelectedResourcesFieldName = "Selected resources";
private const string OrderIdFieldName = "Order ID";
private const string BookingDetailsSectionDefinitionName = "Booking details";
private const string OrderDetailsSectionDefinitionName = "Order details";
private const string NewToWaitingForApprovalTransitionId = "new_to_waiting_for_approval";
private const string PaProcessName = "Service order";
private static readonly TimeSpan OrderMinimumStartOffset = TimeSpan.FromMinutes(30);
private static readonly TimeSpan OrderMinimumDuration = TimeSpan.FromMinutes(5);

private IEngine _engine;
private DomHelper _domHelper;
private ResourceManagerHelper _rmHelper;

private SectionDefinition _bookingDetailsSectionDefinition;

public void Run(Engine engine)
{
// Not doing anything
}

[AutomationEntryPoint(AutomationEntryPointType.Types.OnDomAction)] public void OnDomActionMethod(IEngine engine, ExecuteScriptDomActionContext context)
{
try
{
Setup(engine);
InnerRun(context);
}
catch (Exception ex)
{
FailPopUp(ex.Message);
}
}

private void Setup(IEngine engine)
{
_engine = engine;
_domHelper = new DomHelper(_engine.SendSLNetMessages, ModuleId)
{
SectionDefinitions =
{
ThrowExceptionsOnErrorData = false
},
DomDefinitions = { ThrowExceptionsOnErrorData = false },
DomBehaviorDefinitions = { ThrowExceptionsOnErrorData = false },
DomInstances = { ThrowExceptionsOnErrorData = false },
DomTemplates = { ThrowExceptionsOnErrorData = false },
DomInstanceHistory = { ThrowExceptionsOnErrorData = false }
};

_rmHelper = new ResourceManagerHelper(_engine.SendSLNetSingleResponseMessage);
}

private void InnerRun(ExecuteScriptDomActionContext context)
{
// Check the provided ExecuteScriptDomActionContext
var domInstanceId = ValidateExecuteScriptDomActionContext(context);
if (domInstanceId == null)
{
return;
}

// Retrieve the DomInstance
var domInstance = RetrieveDomInstance(domInstanceId);
if (domInstance == null)
{
FailPopUp($"Retrieving the DomInstance with ID '{domInstanceId}' returned a null object");
return;
}

// Retrieve the SectionDefinition
_bookingDetailsSectionDefinition = GetSectionDefinitionByName(BookingDetailsSectionDefinitionName);
if (_bookingDetailsSectionDefinition == null)
{
FailPopUp($"The SectionDefinition to store the selected resources was not found on the system. (Name: {BookingDetailsSectionDefinitionName})");
return;
}

// Stitch the DomInstance so we have easy access to the configuration objects
LogInformationEvent($"Stitching DomInstance '{domInstance.ID.Id}'");
_domHelper.StitchDomInstances(new List<DomInstance> { domInstance });

// Retrieve start and end time from DomInstance
var startTimeFieldValue = GetFieldValue<DateTime>(domInstance, OrderDetailsSectionDefinitionName, StartTimeFieldName);
if (startTimeFieldValue == null)
{
FailPopUp($"Retrieving value for field '{StartTimeFieldName}' on DomInstance '{domInstance.ID.Id}' returned null");
return;
}
var startTime = startTimeFieldValue.Value;

// Check if the start time is starting at least OrderMinimumStartOffset from now
if (DateTime.UtcNow.Add(OrderMinimumStartOffset) > startTime)
{
FailPopUp($"Please review the start time of your order.{Environment.NewLine}Your order should start in at least {OrderMinimumStartOffset.TotalMinutes} minutes and have a {OrderMinimumDuration.TotalMinutes} minutes minimum duration.");
return;
}

var endTimeFieldValue = GetFieldValue<DateTime>(domInstance, OrderDetailsSectionDefinitionName, EndTimeFieldName);
if (endTimeFieldValue == null)
{
FailPopUp($"Retrieving value for field '{EndTimeFieldName}' on DomInstance '{domInstance.ID.Id}' returned null");
return;
}

var endTime = endTimeFieldValue.Value;

// Check if the start time is not bigger than the end time and has a OrderMinimumDuration
if (startTime.Add(OrderMinimumDuration) > endTime)
{
FailPopUp($"Please review the end time of your order.{Environment.NewLine}Your order should start in at least {OrderMinimumStartOffset.TotalMinutes} minutes and have a {OrderMinimumDuration.TotalMinutes} minutes minimum duration.");
return;
}

// Retrieve eligible resources
var resources = GetEligibleResources(startTime, endTime);
if (resources == null)
{
return;
}

// Let the user select resources
resources = resources.OrderBy(x => x.Name).ToList();
var selectedResources = DrawUi(resources);
if (!selectedResources.Any())
{
FailPopUp("No resources were selected");
return;
}

// Update DomInstance
if (!TryUpdateResourcesOnDomInstance(domInstance, selectedResources))
{
return;
}

// Transition the DomInstance
_domHelper.DomInstances.DoStatusTransition(domInstance.ID, NewToWaitingForApprovalTransitionId);
var traceData = _domHelper.DomInstances.GetTraceDataLastCall();
if (!traceData.HasSucceeded())
{
FailPopUp($"Failed to transition the DomInstance: {traceData}");
return;
}

// Push a PA token
PushPaToken(domInstance);
}

private DomInstanceId ValidateExecuteScriptDomActionContext(ExecuteScriptDomActionContext context)
{
if (context == null)
{
FailPopUp($"The provided {nameof(ExecuteScriptDomActionContext)} is null");
return null;
}

if (context.ActionId == null)
{
FailPopUp($"Unable to retrieve the 'ActionId' on the {nameof(ExecuteScriptDomActionContext)}");
return null;
}

if (context.ContextId == null)
{
FailPopUp($"Unable to retrieve the 'ContextId' on the {nameof(ExecuteScriptDomActionContext)}");
return null;
}

var domInstanceId = context.ContextId as DomInstanceId;
if (domInstanceId == null)
{
FailPopUp($"The provided 'ContextId' is not a '{nameof(DomInstanceId)}'");
return null;
}

if (domInstanceId.ModuleId != ModuleId)
{
FailPopUp($"The provided DomInstance belongs to module '{domInstanceId.ModuleId}', although it should belong to module '{ModuleId}'");
return null;
}

if (domInstanceId.Id == Guid.Empty)
{
FailPopUp($"The provided DomInstance doesn't have a valid ID: {domInstanceId.Id}");
return null;
}

return domInstanceId;
}

private DomInstance RetrieveDomInstance(DomInstanceId domInstanceId)
{
var domInstance = _domHelper.DomInstances.Read(DomInstanceExposers.Id.Equal(domInstanceId)).FirstOrDefault();

var traceData = _domHelper.DomInstances.GetTraceDataLastCall();
if (!traceData.HasSucceeded())
{
FailPopUp($"Unable to retrieve DomInstance with ID '{domInstanceId}': {traceData}");
return null;
}
return domInstance;
}

private ValueWrapper<T> GetFieldValue<T>(DomInstance domInstance, string sectionDefinitionName, string fieldName)
{
foreach (var section in domInstance.Sections)
{
var sectionDefinition = section.GetSectionDefinition();
if (sectionDefinition.GetName() != sectionDefinitionName)
{
break;
}

var fields = sectionDefinition.GetAllFieldDescriptors();
foreach (var field in fields)
{
if (field.Name.Equals(fieldName))
{
return domInstance.GetFieldValue<T>(sectionDefinition, field);
}
}
}

return null;
}

private List<Resource> GetEligibleResources(DateTime start, DateTime end)
{
var pool = GetResourcePool(PoolName);
if (pool == null)
{
return null;
}

LogInformationEvent($"Retrieving the eligible resources in the timespan [{start.ToLocalTime()}, {end.ToLocalTime()}]");
var context = new EligibleResourceContext()
{
ResourceFilter = ResourceExposers.PoolGUIDs.Contains(pool.ID),
TimeRange = new Skyline.DataMiner.Net.Time.TimeRangeUtc(start, end)
};
var result = _rmHelper.GetEligibleResources(context);
var traceData = _rmHelper.GetTraceDataLastCall();
if (!traceData.HasSucceeded())
{
FailPopUp($"Retrieving the eligible resources failed: {traceData}");
return null;
}

if (result == null)
{
FailPopUp($"Retrieving the eligible resources returned a null object");
return null;
}

if (result.EligibleResources.Any())
{
return result.EligibleResources;
}

FailPopUp("There are no eligible resources on the system");
return null;
}

private List<Resource> DrawUi(List<Resource> resources)
{
var uiBuilder = new UIBuilder()
{
Title = "Resource selection",
RowDefs = "a;a;a",
ColumnDefs = "a",
RequireResponse = true
};

var info = new UIBlockDefinition()
{
Type = UIBlockType.StaticText,
ColumnSpan = 1,
Row = 0,
Column = 0,
Text = "Please select the resources you want to book and click the Apply button"
};
uiBuilder.AppendBlock(info);

var list = new UIBlockDefinition()
{
Type = UIBlockType.CheckBoxList,
Row = 1,
Column = 0,
DestVar = "resources"
};
foreach (var resource in resources)
{
list.AddCheckBoxListOption(resource.Name);
}
uiBuilder.AppendBlock(list);

var applyButton = new UIBlockDefinition()
{
Type = UIBlockType.Button,
Row = 2,
Column = 0,
WantsOnChange = true,
Text = "Apply"
};
uiBuilder.AppendBlock(applyButton);

var results = _engine.ShowUI(uiBuilder);

return resources.Where(x => results.GetChecked("resources", x.Name)).ToList();
}

private bool TryUpdateResourcesOnDomInstance(DomInstance domInstance, List<Resource> resources)
{
var fieldDescriptor = _bookingDetailsSectionDefinition.GetAllFieldDescriptors()
.FirstOrDefault(one => one.Name == SelectedResourcesFieldName);
if (fieldDescriptor == null)
{
FailPopUp($"No FieldDescriptor was found with name '{SelectedResourcesFieldName}' " +
$"on the SectionDefinition with ID '{_bookingDetailsSectionDefinition.GetID().Id}'");
return false;
}

domInstance.AddOrUpdateListFieldValue(_bookingDetailsSectionDefinition, fieldDescriptor, resources.Select(x => x.ID).ToList());
_domHelper.DomInstances.Update(domInstance);
var traceData = _domHelper.DomInstances.GetTraceDataLastCall();
if (!traceData.HasSucceeded())
{
FailPopUp($"Unable to update the '{SelectedResourcesFieldName}' field on DomInstance '{domInstance.ID.Id}': {traceData}");
return false;
}

return true;
}

private ResourcePool GetResourcePool(string poolName)
{
var retrievedPool = _rmHelper.GetResourcePools(new ResourcePool() { Name = poolName }).FirstOrDefault();
var traceData = _rmHelper.GetTraceDataLastCall();
if (!traceData.HasSucceeded())
{
FailPopUp($"Unable to retrieve pool '{poolName}': {traceData}");
return null;
}

if (retrievedPool == null)
{
FailPopUp($"Retrieving pool with name '{poolName}' returned null");
return null;
}

return retrievedPool;
}

private void FailPopUp(string message)
{
var uiBuilder = new UIBuilder()
{
Title = "Resource selection failed",
RowDefs = "a;a",
ColumnDefs = "a",
RequireResponse = true
};

var info = new UIBlockDefinition()
{
Type = UIBlockType.StaticText,
ColumnSpan = 1,
Row = 0,
Column = 0,
Text = message
};
uiBuilder.AppendBlock(info);

var applyButton = new UIBlockDefinition()
{
Type = UIBlockType.Button,
Row = 2,
Column = 0,
WantsOnChange = true,
Text = "Close"
};
uiBuilder.AppendBlock(applyButton);

_engine.ShowUI(uiBuilder);
}

private void LogInformationEvent(string message)
{
_engine.GenerateInformation(message);
}

private SectionDefinition GetSectionDefinitionByName(string name)
{
var filter = SectionDefinitionExposers.Name.Equal(name);
var sectionDefinition = _domHelper.SectionDefinitions.Read(filter).FirstOrDefault();
var traceData = _domHelper.DomInstances.GetTraceDataLastCall();
if (!traceData.HasSucceeded())
{
FailPopUp($"Retrieving the SectionDefinition by name ({name}) failed with TraceData: {traceData}");
}

return sectionDefinition;
}

private void PushPaToken(DomInstance domInstance)
{
var title = GetFieldValue<string>(domInstance, OrderDetailsSectionDefinitionName, OrderIdFieldName)?.Value ?? $"Unnamed order ({domInstance.ID.Id})";

try
{
ProcessHelper.PushToken(PaProcessName, title, domInstance.ID);
}
catch (PaProcessNotFoundException)
{
// The process does not exist. It is probably not created yet. Ignore this...
_engine.GenerateInformation(
"The resource selection script for the 'Service Order' app tried to push a PA token for the process " +
$"with name '{PaProcessName}' but the process does not exist yet. Continuing execution...");
}
catch (Exception e)
{
FailPopUp($"Pushing the PA token for process {PaProcessName} failed with an exception: {e.Message}");
}
}
}
}
]]>
</Value>
<!--<Param type="debug">true</Param>-->
<Message />
<Param type="ref">C:\Skyline DataMiner\ProtocolScripts\ProcessAutomation.dll</Param>
</Exe>
</Script>
</DMSScript>

Gerwin van der Kamp [DevOps Enabler] Selected answer as best 14th April 2023
You are viewing 1 out of 3 answers, click here to view all answers.
Please login to be able to comment or post an answer.

My DevOps rank

DevOps Members get more insights on their profile page.

My user earnings

0 Dojo credits

Spend your credits in our swag shop.

0 Reputation points

Boost your reputation, climb the leaderboard.

Promo banner DataMiner DevOps Professiona Program
DataMiner Integration Studio (DIS)
Empower Katas
Privacy Policy • Terms & Conditions • Contact

© 2025 Skyline Communications. All rights reserved.

DOJO Q&A widget

Can't find what you need?

? Explore the Q&A DataMiner Docs

[ Placeholder content for popup link ] WordPress Download Manager - Best Download Management Plugin