This blog post is intended for developers and people doing advanced customizations in Service Manager.
An earlier blog post illustrated how to use the <Form> element in Service Manager's management pack infrastructure to create rich, custom forms for classes and relationships in the CMDB. Custom forms offer complete flexibility in displaying class and relationship information to end users, and they are well-suited to displaying data that spans multiple classes and relationships or requires unique UI elements.
When the data that needs to be displayed originates in an object of one class, presenting an editable table of property-value pairs is often sufficient. To prevent customers from having to develop these simple forms for each class added to a Service Manager installation, Service Manager ships with a Generic Form that renders a property-value display for any class that does not already appear in a custom form.
This blog post will provide background on the forms infrastructure used in our product and the options available to customize the Generic Form.
Part 1: Understanding the forms infrastructure Let's take a look at the <Form> element tag in the ServiceManager.ConfigurationManagement.Library management pack that causes the computer form to display for computer objects in the console.
<Form TypeName="Microsoft.EnterpriseManagement.ServiceManager.ConfigurationManagement.Forms.ComputerForm" Target="Microsoft.Windows.Computer.ProjectionType" ID="ComputerForm" Assembly="ConfigurationManagementFormsAssembly" Accessibility="Public">
Attribute xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office">
Description
TypeName
The qualified name of the .NET Class that contains the form code.
Target
The class (<ClassType>) or type projection (<TypeProjection>) for which the form should display.
ID
A unique identifier for the form element.
Assembly
A reference to an <Assembly> MP element that points to the DLL containing the form code. The Assembly element is defined in the <Resources> section of an MP.
The Assembly element for this form is:
<Assembly ID="ConfigurationManagementFormsAssembly" QualifiedName="Microsoft.EnterpriseManagement.ServiceManager.ConfigurationManagement.Forms" FileName="Microsoft.EnterpriseManagement.ServiceManager.ConfigurationManagement.Forms.dll" Accessibility="Public" />
Accessibility
The accessibility of the form element, set to "Public" here so that this Form element can be referenced by other MPs.
The Target attribute of the form tag links the form to a class or a type projection. When the user selects the "Create" task associated with a view or the "Edit" task associated with an object or object projection, the class to be created or edited is determined. Our UI code then looks for a form that is either (1) targeted to that class or (2) targeted to a type projection that has a seed that is that class. If a form is found, it is displayed. If a form is not found, the check is repeated on each of the parent classes until a form is found.
This logic is summarized in the Figure 1 below:
Figure 1: Form selection process
Note that a form is designated to appear in one of two modes: 1. Pop-out mode, the default, indicates that the form will surface when the "Create" task or the "Edit" task is clicked.
2. Preview mode, which is enabled by adding a category with a special enumeration value and targeting it to the form, indicates that the form will display in the details pane when an item in a grid view is selected.
The search that is performed to find a form for a given object (as depicted in Figure 1) is limited to forms in the desired display mode. For example, when a grid view item is selected, it is determined that a form in preview mode is needed and a search for a form is performed using only the set of forms categorized as preview forms.
The enumeration value used to demarcate a preview form resides in the Microsoft.EnterpriseManagement.ServiceManager.UI.Console management pack. The following category definition, for example, would mark the form named "ClassForm" as a preview form.
<Category ID="someuniqueID" Target="ClassForm" Value="Console!Microsoft.EnterpriseManagement.ServiceManager.UI.Console.OverviewForm" />
Preview and pop-out forms will always be found for a given class because preview and pop-out versions of the Generic Form are targeted to System.Entity, the root class in Service Manager's class model.
Part 2: The Generic Form The Generic Form is a WPF UserControl that consists of up to three tabs:
1. A General tab displays all of the properties of the object that serves as the form's data context. If the data that underlies the form is a projection object, properties are displayed for the seed class object in that projection. Properties in the tab are grouped under their respective classes starting from the top of the class hierarchy (System.Entity) and moving down.
When the object displayed in the form inherits from System.ConfigItem or System.WorkItem:
2. A Related Items tab presents an updatable display of objects related to the object, and
3. A History tab chronicles the changes that have been made to properties on the object and the object’s relationships to other objects.
There are two display modes for the Generic Form. The Generic Preview Form displays property information for the currently selected object in a grid view. Alternatively, the Generic Pop-Out Form displays property information when a class object or projection object is displayed within a form window. These two display modes are juxtaposed below (click to enlarge):
Figure 2: Generic Form displaying a Software Item object in preview mode (left) and pop-out mode (right)
Note that in preview mode, no related items tab or history tab is shown, and the properties in the form are not editable.
The Generic Form appears in four management pack form element (i.e.: <Form> tag) definitions. A preview form and a pop-out form are targeted to the System.Entity base class, one pop-out form is targeted to a type projection with seed class System.ConfigItem, and one pop-out form is targeted to a type projection with seed class System.WorkItem. The pop-out form definitions targeted to the Configuration Item and Work Item type projections are used to populate the Related Items Tab with a standard set of related objects on Configuration Item and Work Item classes.
This is summarized in Figure 3 below.
Figure 3: Occurrence of Generic Form <Form> elements in the class model
Part 3: The Extension Tab When a pop-out form is displayed in a form window using the Create task or the Edit task, a check is made to determine:
1. The class of the object being displayed, and
2. The class to which the form that is being displayed is targeted.
These classes can differ if the form that was selected to display an object is targeted to one of the parent classes of that object (e.g.: displaying an object of a class derived from Change Request in the Change Request form).
If the form that is being displayed is a custom form and is not the Generic Form (which, by default, displays all of an object's properties in the General tab), and classes 1 and 2 differ, an Extension tab is added to the custom form. This tab displays property-value pairs for all classes in the object's class hierarchy that inherit from the form's target class.
The tab also displays (again, only for custom forms) all of the properties of any extension classes in the class hierarchy of the object. These properties are grouped under the extended class.
Suppose, for example, that a sealed MP were imported with class definitions below:
<ClassTypes>
<ClassType ID="Incident_Extension" Base="CoreIncident!System.WorkItem.Incident" Abstract="false" Accessibility="Public" Hosted="false" Extension="true">
<Property ID="incident_extension_1" Type="string" />
<Property ID="incident_extension_2" Type="string" />
<Property ID="incident_extension_3" Type="string" />
</ClassType>
<ClassType ID="Incident_Derived" Base="CoreIncident!System.WorkItem.Incident" Abstract="false" Accessibility="Public" Hosted="false" Extension="false">
<Property ID="incident_derived_1" Type="string" />
<Property ID="incident_derived_2" Type="string" />
</ClassTypes>
If a view were created on the Incident_Derived class and the user attempted to create a new Incident_Derived object using the Create task that appears for the view, the user would see the form in Figure 4 below (click to enlarge):
Figure 4: Generic Form displaying an Incident_Derived object with the extension tab. Extension properties and derived class properties appear in the extension tab.
Since any extension properties of an object are shown in the Extension tab, the Incident_Extension properties are shown in the Extension tab. The Incident_Derived properties also appear in the extension tab because the Incident form is targeted to System.WorkItem.Incident and the object being displayed is of the derived class Incident_Derived.
Below, Figure 5 displays all of the classes (in hierarchical order) of which the Incident_Derived object is a member. Our console assumes that only the non-extension properties that appear in the Incident Form's target class (System.WorkItem.Incident) hierarchy will be displayed in the custom form. Since extension classes and derived classes outside this hierarchy have properties which may not be displayed in the form, the extension tab is added to display the properties of these extended and derived classes.
Figure 5: The properties in the blue classes are assumed to be present in the Incident custom form. Properties in the derived class (red) and the extension class (teal) are added to the extension tab.
To prevent the extension tab from displaying on a form, MP authors can target a category to the form with an Enumeration value in the Microsoft.EnterpriseManagement.ServiceManager.UI.Administration MP:
<EnumerationValue ID="Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideExtensionTab" Accessibility="Public" />
<ManagementPack ContentReadable="true" SchemaVersion="1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<Manifest>
<Identity>
<ID>hidetest</ID>
<Version>7.0.5000.0</Version>
</Identity>
<Name>hidetest</Name>
<References>
<Reference Alias="Admin">
<ID>Microsoft.EnterpriseManagement.ServiceManager.UI.Administration</ID>
<PublicKeyToken>31bf3856ad364e35</PublicKeyToken>
</Reference>
<Reference Alias="Incident">
<ID>ServiceManager.IncidentManagement.Library</ID>
<Version>7.0.5010.0</Version>
</References>
</Manifest>
<Categories>
<Category ID="HideIncidentFormExtensionTab" Target="Incident!System.WorkItem.Incident.ConsoleForm" Value="Admin!Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideExtensionTab" />
</Categories>
</ManagementPack>
Part 4: Additional Generic Form Customizations
1. Disabling the preview pane for a class (and its descendants)
To disable the preview form for an object of a particular class, target a category with the enumeration value
<EnumerationValue ID="Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideDetailsPane" Accessibility="Public" /> (which appears in the Microsoft.EnterpriseManagement.ServiceManager.UI.Administration MP) to the class (not the form) for which the preview pane should not be displayed.
For example, to prevent the Generic Form preview pane (targeted to System.Entity) from appearing when a connector is selected in the grid view under Administration > Connectors, we use the following category:
<Category ID="Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.ConnectorHideDetails" Target="SystemCenter!Microsoft.SystemCenter.Connector" Value="Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideDetailsPane" />
To hide properties in either form mode, an MP author creates a view based on the desired view type in an MP and targets it to the class that contains the properties that should be removed. The configuration supplied to the view specifies the classes for which the properties should not appear and the names of the properties that should not appear. If no target classes are specified, it is assumed that the properties on the target class should be excluded whenever they are displayed (i.e.: for a Generic Form displayed with any class object).
In our console, we use the following view definition to exclude properties of the System.User class in the Generic Preview Form when displaying objects of AD User Groups:
<View ID="UserPreviewExclusionRule" Accessibility="Public" Enabled="true" Target="System!System.User" TypeID="Authoring!PreviewViewType" Visible="true">
<Category>NotUsed</Category>
<Configuration>
<TargetClassList>
<TargetClass>Microsoft.AD.Group</TargetClass>
</TargetClassList>
<PropertyExcludeList>
<Property>FirstName</Property>
<Property>Initials</Property>
<Property>LastName</Property>
<Property>Company</Property>
<Property>Department</Property>
<Property>Office</Property>
<Property>Title</Property>
<Property>EmployeeId</Property>
<Property>StreetAddress</Property>
<Property>City</Property>
<Property>State</Property>
<Property>Zip</Property>
<Property>Country</Property>
<Property>BusinessPhone</Property>
<Property>BusinessPhone2</Property>
<Property>HomePhone</Property>
<Property>HomePhone2</Property>
<Property>Fax</Property>
<Property>Mobile</Property>
<Property>Pager</Property>
</PropertyExcludeList>
</Configuration>
</View>
We use the view definition below to prevent the ObjectStatus property from appearing on the pop-out Generic Form for Configuration Items. If this view definition were not present, users would be able to change the status of a Configuration Item in the forms that appear for Software, Software Updates, and Printers (we use the Generic Form for those classes).
<View ID="ConfigItemExclusionRule" Accessibility="Public" Enabled="true" Target="System!System.ConfigItem" TypeID="Authoring!EditViewType" Visible="true">
<Property>ObjectStatus</Property>
Hi Neil,
I'm extending the incident class. I have followed your instruction strictly on how to hide the extention tab by adding Category ID, Target and Value as Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideExtensionTab. I can successfully import the management pack into service manager however, the extention tab is still visible. Would you please help what do I need further to hide the extention tab once I have extended a class.
Thanks
Dear Neil Lydick ,
We are extending the incident class, as a result, the extention tab automatically shows. We try to hide it by following strictly your instruction above by adding a Category tab with ID, Target and Enumeration value. We can successfully import the management pack into service manager. However, the extention tab is not invisible. Do we need to add any further details? Please help to ping us soon.
Below are 2 cases that you might be encountering. Let me know if these are not related to your problem.
- Neil
====
Case 1: Extension tab is not hidden in DCM form (but IS hidden in normal Incident Form) after importing the MP above
Since the DCM Incident Form is defined in a separate <Form> element, you need to add a Category like
<Category ID="HideDCMIncidentFormExtensionTab" Target="Incident!System.WorkItem.Incident.DCMConsoleForm" Value="Admin!Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideExtensionTab" />
to the "hidetest" MP defined in the post above.
Case 2: Extension tab is not hidden on incident form that was customized using the Authoring Tool
If you've used the Service Manager Authoring Tool to customize the incident form, you'll be importing an MP with a Form element that looks something like this:
...
<Presentation>
<Forms>
<Form ID="CustomForm_2cb04bc7_3b76_4bdd_bb59_782a4f26bbae" Accessibility="Public" Target="CustomForm_2cb04bc7_3b76_4bdd_bb59_782a4f26bbae_TypeProjection" BaseForm="Alias_9c4bf671_3297_442d_a802_4cf702c61c38!System.WorkItem.Incident.ConsoleForm" TypeName="Microsoft.EnterpriseManagement.ServiceManager.Incident.Forms.IncidentFormControl">
<Category>Form</Category>
<Customization>
<ReorderStackPanel StackPanel="UpperGeneralGrid/Index:10">
<Element Name="labelAffectedUser" NewIndex="0" />
</ReorderStackPanel>
</Customization>
</Form>
</Forms>
</Presentation>
Currently, we do not examine the "BaseForm" attribute to see if a Form's BaseForm or any of its parents are targeted by a Category with the HideExtensionTab Enum value. To hide the extension tab on the customized form, you'll need to add a category that targets the customized form directly. This can be done in the customized MP.
(Example for customized form above):
<Category ID="CustomFormHideExtensionTabCategory" Target="CustomForm_2cb04bc7_3b76_4bdd_bb59_782a4f26bbae" Value="Admin!Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideExtensionTab"></Category>
Dear Neil Lydick,
I created Mp with your help, but SCSM do not hidden extensions tab.
Could you give me your email? I will send you my MP.
I was hidden extension tab.
Thanks Neil!
I have a class and a category:
<ClassType ID="Test.EmailEscalation" Accessibility="Public" Abstract="false"
Base="System!System.Entity" Hosted="false" Singleton="false" Extension="false">
<Property ID="EmailEscalationId" Type="guid" AutoIncrement="false" Key="true"
CaseSensitive="false" MaxLength="256" MinLength="0" Required="true" />
<Property ID="Name" Type="string" AutoIncrement="false" Key="false"
<Category ID="Test.Calendar.HideDetailsPane" Target="Test.Calendar"
Value="Administration!Microsoft.EnterpriseManagement.ServiceManager.UI.Administration.Enumeration.HideDetailsPane"/>
I can successfully import the management pack into service manager however, the detail pane is still visible.
Thanks.
Did you mean to target your category to "Test.Calendar" instead of the "Test.EmailEscalation" class that you supplied in your post?
Is the details pane hidden for views on "Test.Calendar"?
<Category ID="Test.EmailEscalation.HideDetailsPane" Target="Test.EmailEscalation"
<View ID="View.EmailEscalation.MainView" Accessibility="Public" Enabled="true"
Target="Test.EmailEscalation" TypeID="Console!GridViewType" Visible="true">
<Data>
<Adapters/>
</Adapters>
<ItemsSource/>
<Criteria />
</Data>
<Columns/>
<ViewStrings/>
I want hidden the details pane when selected item on views "View.EmailEscalation.MainView".
Thanks!
Looking for pointers on below:
I have a included a custom check box field in the service request ticket. When someone clicks on the close button ( to close the service request) I want to check whether the check box is checked and it is not checked it should pop-up a message to the user.