public function DisplayAttachments($oObject, WebPage $oPage, $bEditMode = false) { // Exit here if the class is not allowed if (!$this->IsTargetObject($oObject)) { return; } $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_class = :class AND item_id = :item_id"); $oSet = new DBObjectSet($oSearch, array(), array('class' => get_class($oObject), 'item_id' => $oObject->GetKey())); if ($this->GetAttachmentsPosition() == 'relations') { $sTitle = $oSet->Count() > 0 ? Dict::Format('Attachments:TabTitle_Count', $oSet->Count()) : Dict::S('Attachments:EmptyTabTitle'); $oPage->SetCurrentTab($sTitle); } $oPage->add_style(<<<EOF .attachment { \tdisplay: inline-block; \ttext-align:center; \tfloat:left; \tpadding:5px;\t } .attachment:hover { \tbackground-color: #e0e0e0; } .attachment img { \tborder: 0; } .attachment a { \ttext-decoration: none; \tcolor: #1C94C4; } .btn_hidden { \tdisplay: none; } EOF ); $oPage->add('<fieldset>'); $oPage->add('<legend>' . Dict::S('Attachments:FieldsetTitle') . '</legend>'); if ($bEditMode) { $sIsDeleteEnabled = $this->m_bDeleteEnabled ? 'true' : 'false'; $iTransactionId = $oPage->GetTransactionId(); $sClass = get_class($oObject); $sTempId = session_id() . '_' . $iTransactionId; $sDeleteBtn = Dict::S('Attachments:DeleteBtn'); $oPage->add_script(<<<EOF \tfunction RemoveNewAttachment(att_id) \t{ \t\t\$('#attachment_'+att_id).attr('name', 'removed_attachments[]'); \t\t\$('#display_attachment_'+att_id).hide(); \t\t\$('#attachment_plugin').trigger('remove_attachment', [att_id]); \t\treturn false; // Do not submit the form ! \t} \tfunction ajaxFileUpload() \t{ \t\t//starting setting some animation when the ajax starts and completes \t\t\$("#attachment_loading").ajaxStart(function(){ \t\t\t\$(this).show(); \t\t}).ajaxComplete(function(){ \t\t\t\$(this).hide(); \t\t}); \t\t \t\t/* \t\t\tprepareing ajax file upload \t\t\turl: the url of script file handling the uploaded files fileElementId: the file type of input element id and it will be the index of \$_FILES Array() \t\t\tdataType: it support json, xml \t\t\tsecureuri:use secure protocol \t\t\tsuccess: call back function when the ajax complete \t\t\terror: callback function when the ajax failed \t\t\t */ \t\t\$.ajaxFileUpload \t\t( \t\t\t{ \t\t\t\turl: GetAbsoluteUrlModulesRoot()+'itop-attachments/ajax.attachment.php?obj_class={$sClass}&temp_id={$sTempId}&operation=add', \t\t\t\tsecureuri:false, \t\t\t\tfileElementId:'file', \t\t\t\tdataType: 'json', \t\t\t\tsuccess: function (data, status) \t\t\t\t{ \t\t\t\t\tif(typeof(data.error) != 'undefined') \t\t\t\t\t{ \t\t\t\t\t\tif(data.error != '') \t\t\t\t\t\t{ \t\t\t\t\t\t\talert(data.error); \t\t\t\t\t\t} \t\t\t\t\t\telse \t\t\t\t\t\t{ \t\t\t\t\t\t\tvar sDownloadLink = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?operation=download_document&class=Attachment&id='+data.att_id+'&field=contents'; \t\t\t\t\t\t\t\$('#attachments').append('<div class="attachment" id="display_attachment_'+data.att_id+'"><a href="'+sDownloadLink+'"><img src="'+data.icon+'"><br/>'+data.msg+'<input id="attachment_'+data.att_id+'" type="hidden" name="attachments[]" value="'+data.att_id+'"/></a><br/><input type="button" class="btn_hidden" value="{$sDeleteBtn}" onClick="RemoveNewAttachment('+data.att_id+');"/></div>'); \t\t\t\t\t\t\tif({$sIsDeleteEnabled}) \t\t\t\t\t\t\t{ \t\t\t\t\t\t\t\t\$('#display_attachment_'+data.att_id).hover( function() { \$(this).children(':button').toggleClass('btn_hidden'); } ); \t\t\t\t\t\t\t} \t\t\t\t\t\t\t\$('#attachment_plugin').trigger('add_attachment', [data.att_id, data.msg]); \t\t\t\t\t\t\t \t\t\t\t\t\t\t//alert(data.msg); \t\t\t\t\t\t} \t\t\t\t\t} \t\t\t\t}, \t\t\t\terror: function (data, status, e) \t\t\t\t{ \t\t\t\t\talert(e); \t\t\t\t} \t\t\t} \t\t) \t\t \t\treturn false; \t} EOF ); $oPage->add('<span id="attachments">'); while ($oAttachment = $oSet->Fetch()) { $iAttId = $oAttachment->GetKey(); $oDoc = $oAttachment->Get('contents'); $sFileName = $oDoc->GetFileName(); $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName); $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents'; $oPage->add('<div class="attachment" id="attachment_' . $iAttId . '"><a href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '<input type="hidden" name="attachments[]" value="' . $iAttId . '"/></a><br/> <input id="btn_remove_' . $iAttId . '" type="button" class="btn_hidden" value="Delete" onClick="$(\'#attachment_' . $iAttId . '\').remove();"/> </div>'); } // Suggested attachments are listed here but treated as temporary $aDefault = utils::ReadParam('default', array(), false, 'raw_data'); if (array_key_exists('suggested_attachments', $aDefault)) { $sSuggestedAttachements = $aDefault['suggested_attachments']; if (is_array($sSuggestedAttachements)) { $sSuggestedAttachements = implode(',', $sSuggestedAttachements); } $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE id IN({$sSuggestedAttachements})"); $oSet = new DBObjectSet($oSearch, array()); if ($oSet->Count() > 0) { while ($oAttachment = $oSet->Fetch()) { // Mark the attachments as temporary attachments for the current object/form $oAttachment->Set('temp_id', $sTempId); $oAttachment->DBUpdate(); // Display them $iAttId = $oAttachment->GetKey(); $oDoc = $oAttachment->Get('contents'); $sFileName = $oDoc->GetFileName(); $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName); $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents'; $oPage->add('<div class="attachment" id="display_attachment_' . $iAttId . '"><a href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '<input type="hidden" name="attachments[]" value="' . $iAttId . '"/></a><br/> <input id="btn_remove_' . $iAttId . '" type="button" class="btn_hidden" value="Delete" onClick="RemoveNewAttachment(' . $iAttId . ');"/> </div>'); $oPage->add_ready_script("\$('#attachment_plugin').trigger('add_attachment', [{$iAttId}, '" . addslashes($sFileName) . "']);"); } } } $oPage->add('</span>'); $oPage->add('<div style="clear:both"></div>'); $sMaxUpload = $this->GetMaxUpload(); $oPage->p(Dict::S('Attachments:AddAttachment') . '<input type="file" name="file" id="file" onChange="ajaxFileUpload();"><span style="display:none;" id="attachment_loading"> <img src="../images/indicator.gif"></span> ' . $sMaxUpload); $oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>'); $oPage->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>'); $oPage->add('</fieldset>'); if ($this->m_bDeleteEnabled) { $oPage->add_ready_script('$(".attachment").hover( function() {$(this).children(":button").toggleClass("btn_hidden"); } );'); } } else { $oPage->add('<span id="attachments">'); if ($oSet->Count() == 0) { $oPage->add(Dict::S('Attachments:NoAttachment')); } else { while ($oAttachment = $oSet->Fetch()) { $iAttId = $oAttachment->GetKey(); $oDoc = $oAttachment->Get('contents'); $sFileName = $oDoc->GetFileName(); $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName); $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents'; $oPage->add('<div class="attachment" id="attachment_' . $iAttId . '"><a href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '</a><input type="hidden" name="attachments[]" value="' . $iAttId . '"/><br/> </div>'); } } } }
public function DisplayAttachments($oObject, WebPage $oPage, $bEditMode = false) { // Exit here if the class is not allowed if (!$this->IsTargetObject($oObject)) { return; } $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_class = :class AND item_id = :item_id"); $oSet = new DBObjectSet($oSearch, array(), array('class' => get_class($oObject), 'item_id' => $oObject->GetKey())); if ($this->GetAttachmentsPosition() == 'relations') { $sTitle = $oSet->Count() > 0 ? Dict::Format('Attachments:TabTitle_Count', $oSet->Count()) : Dict::S('Attachments:EmptyTabTitle'); $oPage->SetCurrentTab($sTitle); } $oPage->add_style(<<<EOF .attachment { \tdisplay: inline-block; \ttext-align:center; \tfloat:left; \tpadding:5px;\t } .attachment:hover { \tbackground-color: #e0e0e0; } .attachment img { \tborder: 0; } .attachment a { \ttext-decoration: none; \tcolor: #1C94C4; } .btn_hidden { \tdisplay: none; } .drag_in { \t-webkit-box-shadow:inset 0 0 10px 2px #1C94C4; \tbox-shadow:inset 0 0 10px 2px #1C94C4; } #history .attachment-history-added { \tpadding: 0; \tfloat: none; } EOF ); $oPage->add('<fieldset>'); $oPage->add('<legend>' . Dict::S('Attachments:FieldsetTitle') . '</legend>'); if ($bEditMode) { $sIsDeleteEnabled = $this->m_bDeleteEnabled ? 'true' : 'false'; $iTransactionId = $oPage->GetTransactionId(); $sClass = get_class($oObject); $sTempId = session_id() . '_' . $iTransactionId; $sDeleteBtn = Dict::S('Attachments:DeleteBtn'); $oPage->add_script(<<<EOF \tfunction RemoveAttachment(att_id) \t{ \t\t\$('#attachment_'+att_id).attr('name', 'removed_attachments[]'); \t\t\$('#display_attachment_'+att_id).hide(); \t\t\$('#attachment_plugin').trigger('remove_attachment', [att_id]); \t\treturn false; // Do not submit the form ! \t} EOF ); $oPage->add('<span id="attachments">'); while ($oAttachment = $oSet->Fetch()) { $iAttId = $oAttachment->GetKey(); $oDoc = $oAttachment->Get('contents'); $sFileName = $oDoc->GetFileName(); $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName); $sPreview = $oDoc->IsPreviewAvailable() ? 'true' : 'false'; $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents'; $oPage->add('<div class="attachment" id="display_attachment_' . $iAttId . '"><a data-preview="' . $sPreview . '" href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '<input id="attachment_' . $iAttId . '" type="hidden" name="attachments[]" value="' . $iAttId . '"/></a><br/> <input id="btn_remove_' . $iAttId . '" type="button" class="btn_hidden" value="Delete" onClick="RemoveAttachment(' . $iAttId . ');"/> </div>'); } // Suggested attachments are listed here but treated as temporary $aDefault = utils::ReadParam('default', array(), false, 'raw_data'); if (array_key_exists('suggested_attachments', $aDefault)) { $sSuggestedAttachements = $aDefault['suggested_attachments']; if (is_array($sSuggestedAttachements)) { $sSuggestedAttachements = implode(',', $sSuggestedAttachements); } $oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE id IN({$sSuggestedAttachements})"); $oSet = new DBObjectSet($oSearch, array()); if ($oSet->Count() > 0) { while ($oAttachment = $oSet->Fetch()) { // Mark the attachments as temporary attachments for the current object/form $oAttachment->Set('temp_id', $sTempId); $oAttachment->DBUpdate(); // Display them $iAttId = $oAttachment->GetKey(); $oDoc = $oAttachment->Get('contents'); $sFileName = $oDoc->GetFileName(); $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName); $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents'; $sPreview = $oDoc->IsPreviewAvailable() ? 'true' : 'false'; $oPage->add('<div class="attachment" id="display_attachment_' . $iAttId . '"><a data-preview="' . $sPreview . '" href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '<input id="attachment_' . $iAttId . '" type="hidden" name="attachments[]" value="' . $iAttId . '"/></a><br/> <input id="btn_remove_' . $iAttId . '" type="button" class="btn_hidden" value="Delete" onClick="RemoveAttachment(' . $iAttId . ');"/> </div>'); $oPage->add_ready_script("\$('#attachment_plugin').trigger('add_attachment', [{$iAttId}, '" . addslashes($sFileName) . "']);"); } } } $oPage->add('</span>'); $oPage->add('<div style="clear:both"></div>'); $sMaxUpload = $this->GetMaxUpload(); $oPage->p(Dict::S('Attachments:AddAttachment') . '<input type="file" name="file" id="file"><span style="display:none;" id="attachment_loading"> <img src="../images/indicator.gif"></span> ' . $sMaxUpload); $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.iframe-transport.js'); $oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.fileupload.js'); $oPage->add_ready_script(<<<EOF \$('#file').fileupload({ \t\turl: GetAbsoluteUrlModulesRoot()+'itop-attachments/ajax.attachment.php', \t\tformData: { operation: 'add', temp_id: '{$sTempId}', obj_class: '{$sClass}' }, dataType: 'json', \t\tpasteZone: null, // Don't accept files via Chrome's copy/paste done: function (e, data) { \t\t\tif(typeof(data.result.error) != 'undefined') \t\t\t{ \t\t\t\tif(data.result.error != '') \t\t\t\t{ \t\t\t\t\talert(data.result.error); \t\t\t\t} \t\t\t\telse \t\t\t\t{ \t\t\t\t\tvar sDownloadLink = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?operation=download_document&class=Attachment&id='+data.result.att_id+'&field=contents'; \t\t\t\t\t\$('#attachments').append('<div class="attachment" id="display_attachment_'+data.result.att_id+'"><a data-preview="'+data.result.preview+'" href="'+sDownloadLink+'"><img src="'+data.result.icon+'"><br/>'+data.result.msg+'<input id="attachment_'+data.result.att_id+'" type="hidden" name="attachments[]" value="'+data.result.att_id+'"/></a><br/><input type="button" class="btn_hidden" value="{$sDeleteBtn}" onClick="RemoveAttachment('+data.result.att_id+');"/></div>'); \t\t\t\t\tif({$sIsDeleteEnabled}) \t\t\t\t\t{ \t\t\t\t\t\t\$('#display_attachment_'+data.result.att_id).hover( function() { \$(this).children(':button').toggleClass('btn_hidden'); } ); \t\t\t\t\t} \t\t\t\t\t\$('#attachment_plugin').trigger('add_attachment', [data.result.att_id, data.result.msg]); \t\t\t\t} \t\t\t} }, start: function() { \t\$('#attachment_loading').show(); \t\t}, stop: function() { \t\$('#attachment_loading').hide(); \t\t} }); \t\$(document).bind('dragover', function (e) { \t\tvar bFiles = false; \t\tif (e.dataTransfer && e.dataTransfer.types) \t\t{ \t\t\tfor (var i = 0; i < e.dataTransfer.types.length; i++) \t\t\t{ \t\t\t\tif (e.dataTransfer.types[i] == "application/x-moz-nativeimage") \t\t\t\t{ \t\t\t\t\tbFiles = false; // mozilla contains "Files" in the types list when dragging images inside the page, but it also contains "application/x-moz-nativeimage" before \t\t\t\t\tbreak; \t\t\t\t} \t\t\t\t \t\t\t\tif (e.dataTransfer.types[i] == "Files") \t\t\t\t{ \t\t\t\t\tbFiles = true; \t\t\t\t\tbreak; \t\t\t\t} \t\t\t} \t\t} \t \t\tif (!bFiles) return; // Not dragging files \t\t \t\tvar dropZone = \$('#file').closest('fieldset'); \t\tif (!dropZone.is(':visible')) \t\t{ \t\t\t// Hidden, but inside an inactive tab? Higlight the tab \t\t\tvar sTabId = dropZone.closest('.ui-tabs-panel').attr('aria-labelledby'); \t\t\tdropZone = \$('#'+sTabId).closest('li'); \t\t} \t timeout = window.dropZoneTimeout; \t if (!timeout) { \t dropZone.addClass('drag_in'); \t } else { \t clearTimeout(timeout); \t } \t window.dropZoneTimeout = setTimeout(function () { \t window.dropZoneTimeout = null; \t dropZone.removeClass('drag_in'); \t }, 300); \t}); EOF ); $oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>'); $oPage->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>'); if ($this->m_bDeleteEnabled) { $oPage->add_ready_script('$(".attachment").hover( function() {$(this).children(":button").toggleClass("btn_hidden"); } );'); } } else { $oPage->add('<span id="attachments">'); if ($oSet->Count() == 0) { $oPage->add(Dict::S('Attachments:NoAttachment')); } else { while ($oAttachment = $oSet->Fetch()) { $iAttId = $oAttachment->GetKey(); $oDoc = $oAttachment->Get('contents'); $sFileName = $oDoc->GetFileName(); $sIcon = utils::GetAbsoluteUrlAppRoot() . AttachmentPlugIn::GetFileIcon($sFileName); $sPreview = $oDoc->IsPreviewAvailable() ? 'true' : 'false'; $sDownloadLink = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=download_document&class=Attachment&id=' . $iAttId . '&field=contents'; $oPage->add('<div class="attachment" id="attachment_' . $iAttId . '"><a data-preview="' . $sPreview . '" href="' . $sDownloadLink . '"><img src="' . $sIcon . '"><br/>' . $sFileName . '</a><input type="hidden" name="attachments[]" value="' . $iAttId . '"/><br/> </div>'); } } $oPage->add('</span>'); } $oPage->add('</fieldset>'); $sPreviewNotAvailable = addslashes(Dict::S('Attachments:PreviewNotAvailable')); $iMaxWidth = MetaModel::GetModuleSetting('itop-attachments', 'preview_max_width', 290); $oPage->add_ready_script("\$(document).tooltip({ items: '.attachment a', position: { my: 'left top', at: 'right top', using: function( position, feedback ) { \$( this ).css( position ); }}, content: function() { if (\$(this).attr('data-preview') == 'true') { return('<img style=\"max-width:{$iMaxWidth}px\" src=\"'+\$(this).attr('href')+'\"></img>');} else { return '{$sPreviewNotAvailable}'; }}});"); }
/** * Displays the status (SynchroLog) of the datasource in a graphical manner * @param $oPage WebPage * @return void */ protected function DisplayStatusTab(WebPage $oPage) { $oPage->SetCurrentTab(Dict::S('Core:SynchroStatus')); $sSelectSynchroLog = 'SELECT SynchroLog WHERE sync_source_id = :source_id'; $oSetSynchroLog = new CMDBObjectSet(DBObjectSearch::FromOQL($sSelectSynchroLog), array('start_date' => false), array('source_id' => $this->GetKey())); $oSetSynchroLog->SetLimit(100); // Display only the 100 latest runs if ($oSetSynchroLog->Count() > 0) { $oLastLog = $oSetSynchroLog->Fetch(); $sStartDate = $oLastLog->Get('start_date'); $oLastLog->Get('stats_nb_replica_seen'); $iLastLog = 0; $iDSid = $this->GetKey(); if ($oLastLog->Get('status') == 'running') { // Still running ! $oPage->p('<h2>' . Dict::Format('Core:Synchro:SynchroRunningStartedOn_Date', $sStartDate) . '</h2>'); } else { $sEndDate = $oLastLog->Get('end_date'); $iLastLog = $oLastLog->GetKey(); $oPage->p('<h2>' . Dict::Format('Core:Synchro:SynchroEndedOn_Date', $sEndDate) . '</h2>'); $sOQL = "SELECT SynchroReplica WHERE sync_source_id={$iDSid}"; $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL)); $iCountAllReplicas = $oSet->Count(); $sAllReplicas = "<a href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\">{$iCountAllReplicas}</a>"; $sOQL = "SELECT SynchroReplica WHERE sync_source_id={$iDSid} AND status_last_error !=''"; $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL)); $iCountAllErrors = $oSet->Count(); $sAllErrors = "<a href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\">{$iCountAllErrors}</a>"; $sOQL = "SELECT SynchroReplica WHERE sync_source_id={$iDSid} AND status_last_warning !=''"; $oSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL)); $iCountAllWarnings = $oSet->Count(); $sAllWarnings = "<a href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\">{$iCountAllWarnings}</a>"; $oPage->p('<h2>' . Dict::Format('Core:Synchro:ListReplicas_AllReplicas_Errors_Warnings', $sAllReplicas, $sAllErrors, $sAllWarnings) . '</h2>'); } $oPage->add('<table class="synoptics"><tr><td style="color:#333;vertical-align:top">'); // List all the log entries for the user to select $oPage->add('<h2 style="line-height:55px;">' . Dict::S('Core:Synchro:History') . '</h2>'); $oSetSynchroLog->Rewind(); $oPage->add('<select size="25" onChange="UpdateSynoptics(this.value);">'); $sSelected = ' selected'; // First log is selected by default $sScript = "var aSynchroLog = {\n"; while ($oLog = $oSetSynchroLog->Fetch()) { $sLogTitle = Dict::Format('Core:SynchroLogTitle', $oLog->Get('status'), $oLog->Get('start_date')); $oPage->add('<option value="' . $oLog->GetKey() . '"' . $sSelected . '>' . $sLogTitle . '</option>'); $sSelected = ''; // only the first log is selected by default $aData = $this->ProcessLog($oLog); $sScript .= '"' . $oLog->GetKey() . '": ' . json_encode($aData) . ",\n"; } $sScript .= "end: 'Done'"; $sScript .= "};\n"; $sScript .= <<<EOF \t\t\tvar sLastLog = '{$iLastLog}'; \tfunction ToggleSynoptics(sId, bShow) \t{ \t\tif (bShow) \t\t{ \t\t\t\$(sId).show(); \t\t} \t\telse \t\t{ \t\t\t\$(sId).hide(); \t\t} \t} \t \tfunction UpdateSynoptics(id) \t{ \t\tvar aValues = aSynchroLog[id]; \t\tif (aValues == undefined) return; \t\t \t\tfor (var sKey in aValues) \t\t{ \t\t\t\$('#c_'+sKey).html(aValues[sKey]); \t\t\tvar fOpacity = (aValues[sKey] == 0) ? 0.3 : 1; \t\t\t\$('#'+sKey).fadeTo("slow", fOpacity); \t\t} \t\t//alert('id = '+id+', lastLog='+sLastLog+', id==sLastLog: '+(id==sLastLog)+' obj_updated_errors: '+aValues['obj_updated_errors']); \t\tif ( (id == sLastLog) && (aValues['obj_new_errors'] > 0) ) \t\t{ \t\t\t\$('#new_errors_link').show(); \t\t} \t\telse \t\t{ \t\t\t\$('#new_errors_link').hide(); \t\t} \t\t \t\tif ( (id == sLastLog) && (aValues['obj_updated_errors'] > 0) ) \t\t{ \t\t\t\$('#updated_errors_link').show(); \t\t} \t\telse \t\t{ \t\t\t\$('#updated_errors_link').hide(); \t\t} \t\t \t\tif ( (id == sLastLog) && (aValues['obj_disappeared_errors'] > 0) ) \t\t{ \t\t\t\$('#disappeared_errors_link').show(); \t\t} \t\telse \t\t{ \t\t\t\$('#disappeared_errors_link').hide(); \t\t} \t\t \t\tToggleSynoptics('#cw_obj_created_warnings', aValues['obj_created_warnings'] > 0); \t\tToggleSynoptics('#cw_obj_new_updated_warnings', aValues['obj_new_updated_warnings'] > 0); \t\tToggleSynoptics('#cw_obj_new_unchanged_warnings', aValues['obj_new_unchanged_warnings'] > 0); \t\tToggleSynoptics('#cw_obj_updated_warnings', aValues['obj_updated_warnings'] > 0); \t\tToggleSynoptics('#cw_obj_unchanged_warnings', aValues['obj_unchanged_warnings'] > 0); \t} EOF; $oPage->add_script($sScript); $oPage->add('</select>'); $oPage->add('</td><td style="vertical-align:top;">'); // Now build the big "synoptics" view $aData = $this->ProcessLog($oLastLog); $sNbReplica = $this->GetIcon() . " " . Dict::Format('Core:Synchro:Nb_Replica', "<span id=\"c_nb_replica_total\">{$aData['nb_replica_total']}</span>"); $sNbObjects = MetaModel::GetClassIcon($this->GetTargetClass()) . " " . Dict::Format('Core:Synchro:Nb_Class:Objects', $this->GetTargetClass(), "<span id=\"c_nb_obj_total\">{$aData['nb_obj_total']}</span>"); $oPage->add(<<<EOF \t<table class="synoptics"> \t<tr class="synoptics_header"> \t<td>{$sNbReplica}</td><td> </td><td>{$sNbObjects}</td> \t</tr> \t<tr> EOF ); $sBaseOQL = "SELECT SynchroReplica WHERE sync_source_id=" . $this->GetKey() . " AND status_last_error!=''"; $oPage->add($this->HtmlBox('repl_ignored', $aData, '#999') . '<td colspan="2"> </td>'); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('repl_disappeared', $aData, '#630', 'rowspan="4"') . '<td rowspan="4" class="arrow">=></td>' . $this->HtmlBox('obj_disappeared_no_action', $aData, '#333')); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('obj_deleted', $aData, '#000')); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('obj_obsoleted', $aData, '#630')); $oPage->add("</tr>\n<tr>"); $sOQL = urlencode($sBaseOQL . " AND status='obsolete'"); $oPage->add($this->HtmlBox('obj_disappeared_errors', $aData, '#C00', '', " <a style=\"color:#fff\" href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\" id=\"disappeared_errors_link\">Show</a>")); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('repl_existing', $aData, '#093', 'rowspan="3"') . '<td rowspan="3" class="arrow">=></td>' . $this->HtmlBox('obj_unchanged', $aData, '#393')); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('obj_updated', $aData, '#3C3')); $oPage->add("</tr>\n<tr>"); $sOQL = urlencode($sBaseOQL . " AND status='modified'"); $oPage->add($this->HtmlBox('obj_updated_errors', $aData, '#C00', '', " <a style=\"color:#fff\" href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\" id=\"updated_errors_link\">Show</a>")); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('repl_new', $aData, '#339', 'rowspan="4"') . '<td rowspan="4" class="arrow">=></td>' . $this->HtmlBox('obj_new_unchanged', $aData, '#393')); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('obj_new_updated', $aData, '#3C3')); $oPage->add("</tr>\n<tr>"); $oPage->add($this->HtmlBox('obj_created', $aData, '#339')); $oPage->add("</tr>\n<tr>"); $sOQL = urlencode($sBaseOQL . " AND status='new'"); $oPage->add($this->HtmlBox('obj_new_errors', $aData, '#C00', '', " <a style=\"color:#fff\" href=\"../synchro/replica.php?operation=oql&datasource={$iDSid}&oql={$sOQL}\" id=\"new_errors_link\">Show</a>")); $oPage->add("</tr>\n</table>\n"); $oPage->add('</td></tr></table>'); $oPage->add_ready_script("UpdateSynoptics('{$iLastLog}')"); } else { $oPage->p('<h2>' . Dict::S('Core:Synchro:NeverRun') . '</h2>'); } }
/** * Display the graph inside the given page, with the "filter" drawer above it * @param WebPage $oP * @param hash $aResults * @param string $sRelation * @param ApplicationContext $oAppContext * @param array $aExcludedObjects */ function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects = array(), $sObjClass = null, $iObjKey = null, $sContextKey, $aContextParams = array()) { $aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams); $aExcludedByClass = array(); foreach ($aExcludedObjects as $oObj) { if (!array_key_exists(get_class($oObj), $aExcludedByClass)) { $aExcludedByClass[get_class($oObj)] = array(); } $aExcludedByClass[get_class($oObj)][] = $oObj->GetKey(); } $oP->add("<div class=\"not-printable\">\n"); $oP->add("<div id=\"ds_flash\" class=\"SearchDrawer\" style=\"display:none;\">\n"); if (!$oP->IsPrintableVersion()) { $oP->add_ready_script(<<<EOF \t\$( "#tabbedContent_0" ).tabs({ heightStyle: "fill" }); EOF ); } $oP->add_ready_script(<<<EOF \t\$("#dh_flash").click( function() { \t\t\$("#ds_flash").slideToggle('normal', function() { \$("#ds_flash").parent().resize(); \$("#dh_flash").trigger('toggle_complete'); } ); \t\t\$("#dh_flash").toggleClass('open'); \t}); \$('#ReloadMovieBtn').button().button('disable'); EOF ); $aSortedElements = array(); foreach ($aResults as $sClassIdx => $aObjects) { foreach ($aObjects as $oCurrObj) { $sSubClass = get_class($oCurrObj); $aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass); } } asort($aSortedElements); $idx = 0; foreach ($aSortedElements as $sSubClass => $sClassName) { $oP->add("<span style=\"padding-right:2em; white-space:nowrap;\"><input type=\"checkbox\" id=\"exclude_{$idx}\" name=\"excluded[]\" value=\"{$sSubClass}\" checked onChange=\"\$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_{$idx}\"> " . MetaModel::GetClassIcon($sSubClass) . " {$sClassName}</label></span> "); $idx++; } $oP->add("<p style=\"text-align:right\"><button type=\"button\" id=\"ReloadMovieBtn\" onClick=\"DoReload()\">" . Dict::S('UI:Button:Refresh') . "</button></p>"); $oP->add("</div>\n"); $oP->add("<div class=\"HRDrawer\"></div>\n"); $oP->add("<div id=\"dh_flash\" class=\"DrawerHandle\">" . Dict::S('UI:ElementsDisplayed') . "</div>\n"); $oP->add("</div>\n"); // class="not-printable" $aAdditionalContexts = array(); foreach ($aContextDefs as $sKey => $aDefinition) { $aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => array_key_exists('default', $aDefinition) && $aDefinition['default'] == 'yes'); } $sDirection = utils::ReadParam('d', 'horizontal'); $iGroupingThreshold = utils::ReadParam('g', 5); $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/fraphael.js'); $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot() . 'css/jquery.contextMenu.css'); $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/jquery.contextMenu.js'); $oP->add_linked_script(utils::GetAbsoluteUrlAppRoot() . 'js/simple_graph.js'); try { $this->InitFromGraphviz(); $sExportAsPdfURL = ''; $sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=relation_pdf&relation=' . $sRelation . '&direction=' . ($this->bDirectionDown ? 'down' : 'up'); $oAppcontext = new ApplicationContext(); $sContext = $oAppContext->GetForLink(); $sDrillDownURL = utils::GetAbsoluteUrlAppRoot() . 'pages/UI.php?operation=details&class=%1$s&id=%2$s&' . $sContext; $sExportAsDocumentURL = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=relation_attachment&relation=' . $sRelation . '&direction=' . ($this->bDirectionDown ? 'down' : 'up'); $sLoadFromURL = utils::GetAbsoluteUrlAppRoot() . 'pages/ajax.render.php?operation=relation_json&relation=' . $sRelation . '&direction=' . ($this->bDirectionDown ? 'down' : 'up'); $sAttachmentExportTitle = ''; if ($sObjClass != null && $iObjKey != null) { $oTargetObj = MetaModel::GetObject($sObjClass, $iObjKey, false); if ($oTargetObj) { $sAttachmentExportTitle = Dict::Format('UI:Relation:AttachmentExportOptions_Name', $oTargetObj->GetName()); } } $sId = 'graph'; $sStyle = ''; if ($oP->IsPrintableVersion()) { // Optimize for printing on A4/Letter vertically $sStyle = 'margin-left:auto; margin-right:auto;'; $oP->add_ready_script("\$('.simple-graph').width(18/2.54*96).resizable({ stop: function() { \$(window).trigger('resized'); }});"); // Default width about 18 cm, since most browsers assume 96 dpi } $oP->add('<div id="' . $sId . '" class="simple-graph" style="' . $sStyle . '"></div>'); $aParams = array('source_url' => $sLoadFromURL, 'sources' => $this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects, 'excluded' => $aExcludedByClass, 'grouping_threshold' => $iGroupingThreshold, 'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')), 'export_as_attachment' => array('url' => $sExportAsDocumentURL, 'label' => Dict::S('UI:Relation:ExportAsAttachment'), 'obj_class' => $sObjClass, 'obj_key' => $iObjKey), 'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')), 'labels' => array('export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'), 'export_as_attachment_title' => $sAttachmentExportTitle, 'export' => Dict::S('UI:Button:Export'), 'cancel' => Dict::S('UI:Button:Cancel'), 'title' => Dict::S('UI:RelationOption:Title'), 'untitled' => Dict::S('UI:RelationOption:Untitled'), 'include_list' => Dict::S('UI:RelationOption:IncludeList'), 'comments' => Dict::S('UI:RelationOption:Comments'), 'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'), 'refresh' => Dict::S('UI:Button:Refresh'), 'check_all' => Dict::S('UI:SearchValue:CheckAll'), 'uncheck_all' => Dict::S('UI:SearchValue:UncheckAll'), 'none_selected' => Dict::S('UI:Relation:NoneSelected'), 'nb_selected' => Dict::S('UI:SearchValue:NbSelected'), 'additional_context_info' => Dict::S('UI:Relation:AdditionalContextInfo'), 'zoom' => Dict::S('UI:Relation:Zoom'), 'loading' => Dict::S('UI:Loading')), 'page_format' => array('label' => Dict::S('UI:Relation:PDFExportPageFormat'), 'values' => array('A3' => Dict::S('UI:PageFormat_A3'), 'A4' => Dict::S('UI:PageFormat_A4'), 'Letter' => Dict::S('UI:PageFormat_Letter'))), 'page_orientation' => array('label' => Dict::S('UI:Relation:PDFExportPageOrientation'), 'values' => array('P' => Dict::S('UI:PageOrientation_Portrait'), 'L' => Dict::S('UI:PageOrientation_Landscape'))), 'additional_contexts' => $aAdditionalContexts, 'context_key' => $sContextKey); if (!extension_loaded('gd')) { // PDF export requires GD unset($aParams['export_as_pdf']); } if (!extension_loaded('gd') || is_null($sObjClass) || is_null($iObjKey)) { // Export as Attachment requires GD (for building the PDF) AND a valid objclass/objkey couple unset($aParams['export_as_attachment']); } $oP->add_ready_script("\$('#{$sId}').simple_graph(" . json_encode($aParams) . ");"); } catch (Exception $e) { $oP->add('<div>' . $e->getMessage() . '</div>'); } $oP->add_script(<<<EOF \t\t \tfunction DoReload() \t{ \t\t\$('#ReloadMovieBtn').button('disable'); \t\ttry \t\t{ \t\t\tvar aExcluded = []; \t\t\t\$('input[name^=excluded]').each( function() { \t\t\t\tif (!\$(this).prop('checked')) \t\t\t\t{ \t\t\t\t\taExcluded.push(\$(this).val()); \t\t\t\t} \t\t\t} ); \t\t\t\$('#graph').simple_graph('option', {excluded_classes: aExcluded}); \t\t\t\$('#graph').simple_graph('reload'); \t\t} \t\tcatch(err) \t\t{ \t\t\talert(err); \t\t} \t} EOF ); }
public function Display(WebPage $oP, $aExtraParams = array()) { $oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr); $sTargetClass = $oAttDef->GetTargetClass(); $oTargetObj = MetaModel::GetObject($sTargetClass, $this->m_iObjectId); $oP->set_title("iTop - " . MetaModel::GetName($this->m_sLinkedClass) . " objects linked with " . MetaModel::GetName(get_class($oTargetObj)) . ": " . $oTargetObj->GetRawName()); $oP->add("<div class=\"wizContainer\">\n"); $oP->add("<form method=\"post\">\n"); $oP->add("<div class=\"page_header\">\n"); $oP->add("<input type=\"hidden\" id=\"linksToRemove\" name=\"linksToRemove\" value=\"\">\n"); $oP->add("<input type=\"hidden\" name=\"operation\" value=\"do_modify_links\">\n"); $oP->add("<input type=\"hidden\" name=\"class\" value=\"{$this->m_sClass}\">\n"); $oP->add("<input type=\"hidden\" name=\"linkage\" value=\"{$this->m_sLinkageAttr}\">\n"); $oP->add("<input type=\"hidden\" name=\"object_id\" value=\"{$this->m_iObjectId}\">\n"); $oP->add("<input type=\"hidden\" name=\"linking_attcode\" value=\"{$this->m_sLinkingAttCode}\">\n"); $oP->add("<h1>" . Dict::Format('UI:ManageObjectsOf_Class_LinkedWith_Class_Instance', MetaModel::GetName($this->m_sLinkedClass), MetaModel::GetName(get_class($oTargetObj)), "<span class=\"hilite\">" . $oTargetObj->GetHyperlink() . "</span>") . "</h1>\n"); $oP->add("</div>\n"); $oP->add_script(<<<EOF \t\tfunction OnSelectChange() \t\t{ \t\t\tvar nbChecked = \$('.selection:checked').length; \t\t\tif (nbChecked > 0) \t\t\t{ \t\t\t\t\$('#btnRemove').removeAttr('disabled'); \t\t\t} \t\t\telse \t\t\t{ \t\t\t\t\$('#btnRemove').attr('disabled','disabled'); \t\t\t} \t\t} \t\t \t\tfunction RemoveSelected() \t\t{ \t\t\t\$('.selection:checked').each( \t\t\t\tfunction() \t\t\t\t{ \t\t\t\t\t\$('#linksToRemove').val(\$('#linksToRemove').val() + ' ' + this.value); \t\t\t\t\t\$('#row_'+this.value).remove(); \t\t\t\t} \t\t\t); \t\t\t// Disable the button since all the selected items have been removed \t\t\t\$('#btnRemove').attr('disabled','disabled'); \t\t\t// Re-run the zebra plugin to properly highlight the remaining lines \t\t\t\$('.listResults').trigger('update'); \t\t\t \t\t} \t\t \t\tfunction AddObjects() \t\t{ \t\t\t// TO DO: compute the list of objects already linked with the current Object \t\t\t\$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', { 'operation': 'addObjects', \t\t\t\t\t\t\t\t\t\t'class': '{$this->m_sClass}', \t\t\t\t\t\t\t\t\t\t'linkageAttr': '{$this->m_sLinkageAttr}', \t\t\t\t\t\t\t\t\t\t'linkedClass': '{$this->m_sLinkedClass}', \t\t\t\t\t\t\t\t\t\t'objectId': '{$this->m_iObjectId}' \t\t\t\t\t\t\t\t\t\t}, \t\t\t\tfunction(data) \t\t\t\t{ \t\t\t\t\t\$('#ModalDlg').html(data); \t\t\t\t\tdlgWidth = \$(document).width() - 100; \t\t\t\t\t\$('#ModalDlg').css('width', dlgWidth); \t\t\t\t\t\$('#ModalDlg').css('left', 50); \t\t\t\t\t\$('#ModalDlg').css('top', 50); \t\t\t\t\t\$('#ModalDlg').dialog( 'open' ); \t\t\t\t}, \t\t\t\t'html' \t\t\t); \t\t} \t\t \t\tfunction SearchObjectsToAdd(currentFormId) \t\t{ \t\t\tvar theMap = { 'class': '{$this->m_sClass}', \t\t\t\t\t\t 'linkageAttr': '{$this->m_sLinkageAttr}', \t\t\t\t\t\t 'linkedClass': '{$this->m_sLinkedClass}', \t\t\t\t\t\t 'objectId': '{$this->m_iObjectId}' \t\t\t\t\t\t } \t\t\tif (\$('#'+currentFormId+' :input[name=class]').val() != undefined) \t\t\t{ \t\t\t\ttheMap.linkedClass = \$('#'+currentFormId+' :input[name=class]').val(); \t\t\t} \t\t\t// Gather the parameters from the search form \t\t\t\$('#'+currentFormId+' :input').each( \t\t\t\tfunction(i) \t\t\t\t{ \t\t\t\t\tif (this.name != '') \t\t\t\t\t{ \t\t\t\t\t\ttheMap[this.name] = this.value; \t\t\t\t\t} \t\t\t\t} \t\t\t); \t\t\ttheMap['operation'] = 'searchObjectsToAdd'; \t\t\t \t\t\t// Run the query and display the results \t\t\t\$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap, \t\t\t\tfunction(data) \t\t\t\t{ \t\t\t\t\t\$('#SearchResultsToAdd').html(data); \t\t\t\t\t\$('#SearchResultsToAdd .listResults').tablesorter( { headers: {0: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables \t\t\t\t\t \t\t\t\t}, \t\t\t\t'html' \t\t\t); \t\t\treturn false; \t\t} \t\t \t\tfunction DoAddObjects(currentFormId) \t\t{ \t\t\tvar theMap = { 'class': '{$this->m_sClass}', \t\t\t\t\t\t 'linkageAttr': '{$this->m_sLinkageAttr}', \t\t\t\t\t\t 'linkedClass': '{$this->m_sLinkedClass}', \t\t\t\t\t\t 'objectId': '{$this->m_iObjectId}' \t\t\t\t\t\t } \t\t\t \t\t\t// Gather the parameters from the search form \t\t\t\$('#'+currentFormId+' :input').each( \t\t\t\tfunction(i) \t\t\t\t{ \t\t\t\t\tif ( (this.name != '') && ((this.type != 'checkbox') || (this.checked)) ) \t\t\t\t\t{ \t\t\t\t\t\t//console.log(this.type); \t\t\t\t\t\tarrayExpr = /\\[\\]\$/; \t\t\t\t\t\tif (arrayExpr.test(this.name)) \t\t\t\t\t\t{ \t\t\t\t\t\t\t// Array \t\t\t\t\t\t\tif (theMap[this.name] == undefined) \t\t\t\t\t\t\t{ \t\t\t\t\t\t\t\ttheMap[this.name] = new Array(); \t\t\t\t\t\t\t} \t\t\t\t\t\t\ttheMap[this.name].push(this.value); \t\t\t\t\t\t} \t\t\t\t\t\telse \t\t\t\t\t\t{ \t\t\t\t\t\t\ttheMap[this.name] = this.value; \t\t\t\t\t\t} \t\t\t\t\t} \t\t\t\t} \t\t\t); \t\t\ttheMap['operation'] = 'doAddObjects'; \t\t\t \t\t\t// Run the query and display the results \t\t\t\$.post( GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', theMap, \t\t\t\tfunction(data) \t\t\t\t{ \t\t\t\t\t//console.log('Data: ' + data); \t\t\t\t\tif (data != '') \t\t\t\t\t{ \t\t\t\t\t\t\$('#empty_row').remove(); \t\t\t\t\t} \t\t\t\t\t\$('.listResults tbody').append(data); \t\t\t\t\t\$('.listResults').trigger('update'); \t\t\t\t\t\$('.listResults').tablesorter( { headers: {0: false}}, widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables \t\t\t\t}, \t\t\t\t'html' \t\t\t); \t\t\t\$('#ModalDlg').dialog('close'); \t\t\treturn false; \t\t} \t\t \t\tfunction InitForm() \t\t{ \t\t\t// make sure that the form is clean \t\t\t\$('.selection').each( function() { this.checked = false; }); \t\t\t\$('#btnRemove').attr('disabled','disabled'); \t\t\t\$('#linksToRemove').val(''); \t\t} \t\t \t\tfunction SubmitHook() \t\t{ \t\t\tvar the_form = this; \t\t\tSearchObjectsToAdd(the_form.id); \t\t\treturn false; \t\t} EOF ); $oP->add_ready_script("InitForm();"); $oFilter = new DBObjectSearch($this->m_sClass); $oFilter->AddCondition($this->m_sLinkageAttr, $this->m_iObjectId, '='); $oSet = new DBObjectSet($oFilter); $aForm = array(); while ($oCurrentLink = $oSet->Fetch()) { $aRow = array(); $key = $oCurrentLink->GetKey(); $oLinkedObj = MetaModel::GetObject($this->m_sLinkedClass, $oCurrentLink->Get($this->m_sLinkingAttCode)); $aForm[$key] = $this->GetFormRow($oP, $oLinkedObj, $oCurrentLink); } //var_dump($aTableLabels); //var_dump($aForm); $this->DisplayFormTable($oP, $this->m_aTableConfig, $aForm); $oP->add("<span style=\"float:left;\"> <img src=\"../images/tv-item-last.gif\"> <input id=\"btnRemove\" type=\"button\" value=\"" . Dict::S('UI:RemoveLinkedObjectsOf_Class') . "\" onClick=\"RemoveSelected();\" >"); $oP->add(" <input id=\"btnAdd\" type=\"button\" value=\"" . Dict::Format('UI:AddLinkedObjectsOf_Class', MetaModel::GetName($this->m_sLinkedClass)) . "\" onClick=\"AddObjects();\"></span>\n"); $oP->add("<span style=\"float:right;\"><input id=\"btnCancel\" type=\"button\" value=\"" . Dict::S('UI:Button:Cancel') . "\" onClick=\"BackToDetails('" . $sTargetClass . "', " . $this->m_iObjectId . ");\">"); $oP->add(" <input id=\"btnOk\" type=\"submit\" value=\"" . Dict::S('UI:Button:Ok') . "\"></span>\n"); $oP->add("<span style=\"clear:both;\"><p> </p></span>\n"); $oP->add("</div>\n"); $oP->add("</form>\n"); if (isset($aExtraParams['StartWithAdd']) && $aExtraParams['StartWithAdd']) { $oP->add_ready_script("AddObjects();"); } }
/** * Display the history of bulk imports */ static function DisplayImportHistory(WebPage $oPage, $bFromAjax = false, $bShowAll = false) { $sAjaxDivId = "CSVImportHistory"; if (!$bFromAjax) { $oPage->add('<div id="' . $sAjaxDivId . '">'); } $oPage->p(Dict::S('UI:History:BulkImports+') . ' <span id="csv_history_reload"></span>'); $oBulkChangeSearch = DBObjectSearch::FromOQL("SELECT CMDBChange WHERE origin IN ('csv-interactive', 'csv-import.php')"); $iQueryLimit = $bShowAll ? 0 : appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $oBulkChanges = new DBObjectSet($oBulkChangeSearch, array('date' => false), array(), null, $iQueryLimit); $oAppContext = new ApplicationContext(); $bLimitExceeded = false; if ($oBulkChanges->Count() > appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit())) { $bLimitExceeded = true; if (!$bShowAll) { $iMaxObjects = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $oBulkChanges->SetLimit($iMaxObjects); } } $oBulkChanges->Seek(0); $aDetails = array(); while ($oChange = $oBulkChanges->Fetch()) { $sDate = '<a href="csvimport.php?step=10&changeid=' . $oChange->GetKey() . '&' . $oAppContext->GetForLink() . '">' . $oChange->Get('date') . '</a>'; $sUser = $oChange->GetUserName(); if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches)) { $sUser = $aMatches[1]; } else { $sUser = $oChange->Get('userinfo'); } $oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpCreate WHERE change = :change_id"); $oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey())); $iCreated = $oOpSet->Count(); // Get the class from the first item found (assumption: a CSV load is done for a single class) if ($oCreateOp = $oOpSet->Fetch()) { $sClass = $oCreateOp->Get('objclass'); } $oOpSearch = DBObjectSearch::FromOQL("SELECT CMDBChangeOpSetAttribute WHERE change = :change_id"); $oOpSet = new DBObjectSet($oOpSearch, array(), array('change_id' => $oChange->GetKey())); $aModified = array(); $aAttList = array(); while ($oModified = $oOpSet->Fetch()) { // Get the class (if not done earlier on object creation) $sClass = $oModified->Get('objclass'); $iKey = $oModified->Get('objkey'); $sAttCode = $oModified->Get('attcode'); $aAttList[$sClass][$sAttCode] = true; $aModified["{$sClass}::{$iKey}"] = true; } $iModified = count($aModified); // Assumption: there is only one class of objects being loaded // Then the last class found gives us the class for every object if ($iModified > 0 || $iCreated > 0) { $aDetails[] = array('date' => $sDate, 'user' => $sUser, 'class' => $sClass, 'created' => $iCreated, 'modified' => $iModified); } } $aConfig = array('date' => array('label' => Dict::S('UI:History:Date'), 'description' => Dict::S('UI:History:Date+')), 'user' => array('label' => Dict::S('UI:History:User'), 'description' => Dict::S('UI:History:User+')), 'class' => array('label' => Dict::S('Core:AttributeClass'), 'description' => Dict::S('Core:AttributeClass+')), 'created' => array('label' => Dict::S('UI:History:StatsCreations'), 'description' => Dict::S('UI:History:StatsCreations+')), 'modified' => array('label' => Dict::S('UI:History:StatsModifs'), 'description' => Dict::S('UI:History:StatsModifs+'))); if ($bLimitExceeded) { if ($bShowAll) { // Collapsible list $oPage->add('<p>' . Dict::Format('UI:CountOfResults', $oBulkChanges->Count()) . ' <a class="truncated" onclick="OnTruncatedHistoryToggle(false);">' . Dict::S('UI:CollapseList') . '</a></p>'); } else { // Truncated list $iMinDisplayLimit = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit()); $sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oBulkChanges->Count()); $sLinkLabel = Dict::S('UI:DisplayAll'); $oPage->add('<p>' . $sCollapsedLabel . ' <a class="truncated" onclick="OnTruncatedHistoryToggle(true);">' . $sLinkLabel . '</p>'); $oPage->add_ready_script(<<<EOF \t\$('#{$sAjaxDivId} table.listResults').addClass('truncated'); \t\$('#{$sAjaxDivId} table.listResults tr:last td').addClass('truncated'); EOF ); $sAppContext = $oAppContext->GetForLink(); $oPage->add_script(<<<EOF \tfunction OnTruncatedHistoryToggle(bShowAll) \t{ \t\t\$('#csv_history_reload').html('<img src="../images/indicator.gif"/>'); \t\t\$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data) \t\t\t{ \t\t\t\t\$('#{$sAjaxDivId}').html(data); \t\t\t\tvar table = \$('#{$sAjaxDivId} .listResults'); \t\t\t\ttable.tableHover(); // hover tables \t\t\t\ttable.tablesorter( { widgets: ['myZebra', 'truncatedList']} ); // sortable and zebra tables \t\t\t} \t\t); \t} EOF ); } } else { // Normal display - full list without any decoration } $oPage->table($aConfig, $aDetails); if (!$bFromAjax) { $oPage->add('</div>'); } }