Work Centers offer you a simpler, task-based, and role-based interface that is responsive on desktops, notebooks, tablets, and smartphones.
Several related tools are available for activities such as designing data sets for business analysis
, creating inspection forms, and quickly entering service requests.
But as of today there is not much documentation or tool support available to customize work
centers ,
IBM have a work center designer in their road map but that's at least an year away.
So I am covering simple use case for customization Work Center which may be helpful to
community while we await on more detailed tooling and documentation support from IBM available
publicly.
Recently my client had requirement for customized Inspection Work Center having text response field to
be enhanced as below :
- Text Response filed should be customized to use multiline text box instead of Out-of-Box textbox.
- Newly updated text response filed control/component should have default width and
- height to display larger size component.
- Text Response field should be able to handle 10000 characters instead of default limited size.
achieve this customization.
Now lets take look on which all artifacts will need to be changed to achieve this:
So we will need to replace default “maximo-text” component for free-form
response
field on Inspection Work Center forms, to use “maximo-textarea” component.
Also additionally “maximo-textarea” component needs be enhanced or customized
to have
different increased default width and height , as well 1000 character limit on the
text area as requested by Client.
So we will need to change below files
1. Take back up of existing files.
- <maximo-install-root>\maximo-x\script\maximocards\inspection\inspector\maximo-response-field\maximo-response-field.js
- <maximo-install-root>\maximo-x\script\maximocomponents\maximo-textarea\maximo-textarea-css.html
- <maximo-install-root>\maximo-x\script\maximocomponents\maximo-textarea\maximo-textarea.js
2. Apply Changes to files :
**********************************************************************************
a) maximo-response-field.js :
Update respective methods to use "maximo-textarea" components by replacing "maximo-text"
component
setTextResponse: function(response) {
var input = this.$.responseContainer.querySelector('maximo-textarea');
input.value = response;
input.fire('change');
this.notifyResponseSet();
},
buildTextInput: function() {
var self = this;
var resultRecord = this.resultrecord;
var itemfield = this.item;
var responseFieldType = this.getResponseFieldType(
itemfield.fieldtype_maxvalue, itemfield.metertype_maxvalue);
// Create component attributes
var attrs = {};
attrs.id = itemfield._id + 'textresponse';
attrs.placeholder = $M.localize('uitext', 'mxapiinspection',
'enter_your_answer-here');
attrs.type = 'text';
attrs.label = itemfield.description;
// Set required
attrs.readonly = false;
if (!resultRecord || resultRecord.status_maxvalue === 'COMPLETED')
{
attrs.readonly = true;
}
// Set require flag
if (itemfield.required === true) {
this._setRequired(true);
} else {
this._setRequired(false);
}
// Create component
var responseField = Polymer.Base.create('maximo-textarea', attrs);
// Fetching response
//var response = this.filterResult(resultRecord, itemfield);
var response = itemfield._outerinspfieldresult;
// Add change listener on input
responseField.addEventListener('change', function(event) {
event.stopPropagation();
self.clearMessages();
var lastResponse = self.fieldResponse ? self.fieldResponse : response;
var payload = {
inspresult: resultRecord,
respfield: self.prepareResponseField(resultRecord, itemfield,
this.value, lastResponse),
successCallback: self.updateResponseSuccessHandler.bind(self),
errorCallback: self.updateResponseFailureHandler.bind(self)
};
self.fire('update-response-field', payload);
});
// Prevent scroll to top
responseField.$.label.addEventListener('click', this.preventScroll);
// Append input in document
this.$.responseContainer.appendChild(responseField);
// Set proper ID
if ('_setIdentification' in responseField) {
responseField._setIdentification();
}
// Need to be after inserted in DOM tree
// Set value and store it locally
if (response) {
// Store response object
if (response[responseFieldType] !== undefined) {
var respVal = response[responseFieldType];
responseField.value = respVal;
// Unecessary since completion has been processed before in container
this.async(function() {
this._responseChanged(responseFieldType, response);
});
}
}
// Add style
responseField.setAttribute('style', 'text-align:left;');
responseField.$.input.setAttribute('style', 'font-size:129%;width:400%;
hight:450%');
responseField.$.label.setAttribute('style', 'font-size:129%;');
if (!responseField.label) {
responseField.$.label.setAttribute('hidden', true);
}
},
restorePreviousValue: function() {
var type = this.item.fieldtype_maxvalue;
var responsefield = this.getResponseFieldType(
this.item.fieldtype_maxvalue, this.item.metertype_maxvalue);
var input;
if (type === 'TR') {
input = Polymer.dom(this.$.responseContainer).querySelector('maximo-textarea');
input.value = this.fieldResponse[responsefield];
} else if (type === 'SE') {
input = Polymer.dom(this.$.responseContainer).querySelector('maximo-text');
input.value = this.fieldResponse[responsefield];
} else if (type === 'FU') {
console.warn('Problem to fetch inspection result data');
} else if (type === 'MM') {
var meterType = this.item.metertype_maxvalue;
if (meterType === 'CHARACTERISTIC') {
input = Polymer.dom(this.$.responseContainer).querySelector('maximo-select');
} else {
input = Polymer.dom(this.$.responseContainer).querySelector('maximo-text');
}
input.value = this.fieldResponse[responsefield];
}
},
buildGenericInput: function() {
var resultRecord = this.resultrecord;
var itemfield = this.item;
$j(this.$.responseContainer).empty();
//filter fields down to only ones that exist on result record
var self = this;
var responseArray = [];
if (resultRecord && resultRecord.inspfieldresult && itemfield.inspfieldresult)
{
responseArray = itemfield.inspfieldresult.filter(function(el)
{
return el.orgid === resultRecord.orgid &&
el.resultnum === resultRecord.resultnum;
});
}
var responseField = '';
var responseFieldType = this
.getResponseFieldType(itemfield.fieldtype_maxvalue);
if (itemfield.fieldtype_maxvalue === 'TR' ||
itemfield.fieldtype_maxvalue === 'SE') {
responseField = Polymer.Base.create('maximo-textarea', {
'id': itemfield._id + 'textresponse'
});
if (itemfield.fieldtype_maxvalue === 'TR') {
responseField.placeholder = $M.localize('uitext', 'mxapiinspection',
'enter_your_answer_here');
} else {
responseField.placeholder = $M.localize('uitext', 'mxapiinspresult',
'numeric_response');
}
} else {
var placeholdertext = $M.localize('uitext', 'mxapibase', 'select_option');
responseField = Polymer.Base.create('maximo-select', {
'id': itemfield._id + 'responseFieldresponse','placeholder':
placeholdertext
});
}
if (resultRecord && resultRecord.inspfieldresult && responseArray[0] &&
responseArray.length > 0) {
if (!responseArray || responseArray.length === 0 ||
responseArray[0][responseFieldType] === undefined) {
responseField.setAttribute('value', '');
} else {
responseField.setAttribute('value', responseArray[0][responseFieldType]);
}
} else {
responseField.setAttribute('value', '');
}
//Dynamically build Text, Numeric and Single Select Response Fields
if (itemfield.fieldtype_maxvalue === 'TR' ||
itemfield.fieldtype_maxvalue === 'SE') {
responseField.label = itemfield.description;
if (itemfield.fieldtype_maxvalue === 'TR') {
responseField.setAttribute('id', itemfield._id + 'textresponse');
responseField.setAttribute('type', 'text');
} else if (itemfield.fieldtype_maxvalue === 'SE') {
responseField.setAttribute('id', itemfield._id + 'numericresponse');
responseField.setAttribute('type', 'text');
$j(responseField.$.input).attr('class',
'input-no-spinner style-scope maximo-text');
$j(responseField.$.input).attr('step', 'any');
}
$j(responseField.$.input).on('change', function(e) {
self._updateResponseField(e);
self.domHost.fire('maximo-response-field-changed', e);
});
if (!this.resultrecord) {
responseField.setAttribute('readonly', true);
} else {
$j(responseField.$.input)
.keyup(
function() {
if (responseField.required === true && !responseField.label) {
if ($j(this).val().length > 0) {
$j(responseField.$.input)[0].parentElement.removeAttribute
('required');
$j(responseField.$.input)[0].parentElement.setAttribute
('notrequired', '');
} else {
$j(responseField.$.input)[0].parentElement.removeAttribute
('notrequired');
$j(responseField.$.input)[0].parentElement.setAttribute
('required', '');
}
}
//only process for single numeric entry
if ($j(this)[0].parentElement.parentElement.parentElement.
parentElement.parentElement.item.fieldtype_maxvalue === 'SE')
{
var num = $j(this).val();
var reg = new RegExp('^(?!.*?\\.{2})
(?!.*\,\,)(?!.*--)[0-9\.\,\-\/]+$');
if (!reg.test(num)) {
num = num.substring(0, num.length - 1);
$j(this).val(num);
}
//needed for edge browser to trigger change event when field is
cleared
if (num === '') {
$j(responseField.$.input).trigger('change');
}
}
});
}
if (!this.resultrecord) {
if (itemfield.required === true) {
$j(responseField.$.input)[0].parentElement.setAttribute('required','');
}
} else {
if (itemfield.required === true && !itemfield.description) {
if (responseField.getAttribute('value').length > 0) {
$j(responseField.$.input)[0].parentElement.removeAttribute('required');
$j(responseField.$.input)[0].parentElement.setAttribute('notrequired', '');
} else {
$j(responseField.$.input)[0].parentElement.removeAttribute('notrequired');
$j(responseField.$.input)[0].parentElement.setAttribute('required','');
}
}
}
$j(responseField.$.input).attr('style', 'font-size:129%;width:50%;');
$j(responseField.$.input).attr('id', itemfield._id + '_input_response');
if (resultRecord && resultRecord.status_maxvalue === 'COMPLETED') {
responseField.setAttribute('readonly', 'true');
}
} else if (itemfield.fieldtype_maxvalue === 'SO') {
//SINGLE SELECT SECTION a.k.a Single Option
var res = [];
if (resultRecord && resultRecord.status_maxvalue === 'COMPLETED') {
$j(responseField.$.select).attr('disabled', 'disabled');
}
//sort collection to make sure data is in sequence order
itemfield.inspfieldoption.sort(function(a, b) {
return parseFloat(a.sequence) - parseFloat(b.sequence);
});
itemfield.inspfieldoption.forEach(function(inspfieldoption) {
res.push(inspfieldoption.description);
});
var valuelist = res.join(',');
//responseField.setAttribute('id',itemfield._id+'responseFieldresponse');
responseField.label = itemfield.description;
responseField.values = valuelist;
if (this.resultrecord) {
$j(responseField.$.select).on('change',function(e) {
if (responseField.required === true && !responseField.label) {
if ($j(this).val().length > 0) {
$j(responseField.$.select)[0].parentElement.removeAttribute
('required');
$j(responseField.$.select)[0].parentElement.setAttribute
('notrequired', '');
} else {
$j(responseField.$.select)[0].parentElement.removeAttribute
('notrequired');
$j(responseField.$.select)[0].parentElement.setAttribute
('required', '');
}
}
self._updateResponseField(e);
self.domHost.fire('maximo-response-field-changed', e);
});
} else {
responseField.setAttribute('readonly', true);
}
if (itemfield.required === true && !itemfield.description) {
if (responseField.getAttribute('value').length > 0) {
$j(responseField.$.select)[0].parentElement.removeAttribute('required');
$j(responseField.$.select)[0].parentElement.setAttribute('notrequired', '');
} else {
$j(responseField.$.select)[0].parentElement
.removeAttribute('notrequired');
$j(responseField.$.select)[0].parentElement.setAttribute('required','');
}
}
$j(responseField.$.select).attr('id', itemfield._id + '_select_option');
} else {
console.warn('Unable to build field type');
}
//set required flag on required response fields
if (itemfield.required === true) {
responseField.setAttribute('required', '');
//hide required flag when label is empty
if (!responseField.label) {
$j(responseField.$.label).attr('hidden', '');
}
}
responseField.setAttribute('style', 'text-align:left;');
$j(responseField.$.label).attr('style', 'font-size:129%;');
this.parentElement.setAttribute('style',
'padding-left:21px;padding-bottom:20px;');
responseField.fieldEvent = itemfield;
this.$.responseContainer.appendChild(responseField);
},
*********************************************************************************
b) maximo-textarea-css.html :
<dom-module id="maximo-textarea-css">
<template>
<style>
:host {
--font-style:normal;
--font-size:14px;
}
.font-style{
font-style:var(--font-style);
}
.wrapper {
margin: 0px;
display: inline-block;
}
textarea {
padding: 10px 3px;
transition: all .5s;
border: 1px solid var(--Cool-gray30);
outline: none;
margin-bottom: 3px;
text-align: left;
overflow-y:auto;
width: 1000px;
background-color: var(--Primary-white);
display: inline-block;
box-sizing: border-box;
font-size: var(--font-size);
}
textarea:focus {
border-color: var(--Primary-blue30);
}
textarea[readonly]{
background: var(--Neutral-gray2);
}
label {
color: var(--Primary-gray50);
display: block;
}
label[required]:before {
content: '* ';
font-size: 110%;
color : orange;
}
/* Custom class for textarea */
@media (max-width: 1024px){
.textarea-maxWidth{
max-width: var(--max-width);
float: var(--float-left);
}
}
</style>
</template>
</dom-module>
**********************************************************************************
c) maximo-textarea.js :
Polymer({
is: 'maximo-textarea',
behaviors : [ BaseComponent , DirtyBehavior],
properties: {
/** Set component to readonly */
readonly: {
type: Boolean,
value: false,
observer: '_setReadonly'
},
/** turn off spell checking */
spellCheckOff: {
type: Boolean,
value: false
},
/** Set component to required */
required: {
type: Boolean,
value: false,
observer: '_setRequired'
},
/** Set component placeholder */
placeholder: {
type: String,
value: '',
notify: true
},
_internalplaceholder: {
type: String,
value: ''
},
/** Value of component */
value: {
type: String,
value: '',
notify : true,
observer: '_updateTextarea'
},
/** Set the width of the textarea */
width: {
type: String,
value : '1000px'
},
/** Set the height of the textarea */
height: {
type: String,
value : '300px'
},
// Length for text area updated to 10000
maxlength: {
type: Number,
value: 10000
},
resize: {
type: String
}
},
ready: function() {
if(this.readonly){
$j(this.$.input).prop('readonly', 'readonly');
}
$j(this.$.label).attr({'for':this.$.input.id});
$j(this.$.input).attr({'name':this.$.input.id});
if(this.width){
$j(this.$.input).css({'width':this.width});
}
if(this.height){
$j(this.$.input).css({'height':this.height});
}
if(this.spellCheckOff){
$j(this.$.input).attr({'spellcheck':'false'});
}if(this.resize){
$j(this.$.input).css({'resize':this.resize});
}
},
attached: function(){
if(this.placeholder){
this._internalplaceholder = ' '+this.placeholder;
}
this._setReadonly(this.readonly?this.readonly:false);
this._setRequired(this.required);
},
_setReadonly: function(val){
$j(this.$.input).attr({'readonly':val,'aria-readonly':val});
},
_setRequired: function(val){
$j(this.$.input).attr({'aria-required':val});
},
_onChange: function(e){
this.value = $j(this.$.input).val();
},
_updateTextarea: function(value){
if (this.value !== undefined) {
$j(this.$.input).val(value);
$j(this.$.input).toggleClass('placeHolder',
this.value.trim()==='');
}
},
_onblur: function(e){
this.placeholder = this._internalplaceholder;
$j(this.$.input).toggleClass('placeHolder', this.value.trim()==='');
},
_onfocus: function(e){
if(!this.readonly){
this.placeholder = '';
$j(this.$.input).toggleClass('placeHolder', false);
}
},
});
**********************************************************************************
3. Take back up of existing maximo-x.war file
(<maximo-install-root>\maximo\deployment\default)
4. Run the command buildmaximo-xwar.bat/sh
(<maximo-install-root>\maximo\deployment)
5. Deploy newly built maximo-x.war file to Application server.
Now we can Test the change :
Login and launch inspection work center and open any existing inspection form
and observe default textbox response field is changed to text area and also
it has 10000 characters limit :
Next we will cover some additional customization which will need code changes
to display different tabs on Inspection Work Center to display additional status wise
filtered inspection records.
Cheers !!