Technology, Continued...

Ramblings about business, technology, development and my life

Copying Azure VMs from one account to another

I had to copy my VM blob from one account to another.  I wanted a way that wouldn’t require me to download the vhd locally, just to then have to turn around and upload it again.  Instead, I wanted to be able to have the copy done within the Azure cloud itself.  Fortunately, I found free software to do just that.  It’s called AZCopy.  Here’s the link you need:

http://blogs.msdn.com/b/windowsazurestorage/archive/2013/04/01/azcopy-using-cross-account-copy-blob.aspx

You don’t have to install anything.  Just run it from the command prompt.  Here’s the syntax of the command I used:

   1: AzCopy https://<sourceaccount>.blob.core.windows.net/<sourcecontainer>/ https://<destaccount>.blob.core.windows.net/<destcontainer>/  /sourcekey:<key> /destkey:<key> /S

I’m not sure when you have to use https and when you don’t.  My paths in Azure didn’t show https, but when I tried to copy to my destination, I kept getting the error below.

Error parsing destination location "http://dest.blob.core.windows.net/vhds/": The underlying connection was closed: An unexpected error occurred on a receive.

Once I changed it to https, it worked great.  Here’s the output of my results.

C:\_utilities>azcopy http://source.blob.core.windows.net/vhds/ https://dest.blob.core.windows.net/vhds/ /sourcekey:srckey /destkey:dstkey /S

Transferring files /

Transfer summary:
-----------------
Total files transferred: 1
Transfer successfully:   1
Transfer failed:         0

127GB copied in just a few minutes!  Perfect.

SSRS 2012 Tile View Customization

I don’t know about you, but I don’t like the default tile view in SSRS 2012.  First, I feel like there’s too much white space.  Second, I want my report titles to wrap.  And finally, I don’t want the dropdowns on the tile view.  I’m constantly getting them when I just want to view the report (especially on touch devices), and it confuses my users.

Desired Outcome

So, I want to customize SSRS report list view to change the following:

image

 

To be more like this.  Wrapping, check.  Less whitespace, check.  No dropdown, check.

image

 

Again, importantly, I DO want the dropdown in the Details view, and the changes below do so.

Instructions

To do this, we have to edit the report javascript and css files.  I found more info here:

http://msdn.microsoft.com/en-us/library/ms345247(v=sql.110).aspx

On my server, the files were under the following directory:

C:\Program Files\Microsoft SQL Server\MSRS11.MSSQLSERVER\Reporting Services\ReportManager

Under this folder is a js and a styles folder.  The js folder has ReportingServices.js, while the styles folder has ReportingServices.css.  These are the two files we’ll be editing.

ReportingServices.js

Warning: this is a hack done in about 30 minutes.  I haven’t tested on different browsers or in all scenarios, so use at your own risk.

ReportingServices.js is compressed, so it’s rather jumbled.  Instead of finding the existing functions that need to be changed, just go to the end and insert the following javascript:

   1: //jw 2013-07-30
   2: //customized this to stop dropdown on tile view while still allowing it on details view
   3:  
   4: //this will stop the custom formatting for the dropdown
   5: function ChangeReportItemStyleOnMouseOver(a, c, b) {
   6:     var tagname = GetUnSelectedParentTagName(this);
   7:  
   8:     if (tagname == "DIV") {
   9:         return true;
  10:     }
  11:     else {
  12:         _unselectedItemStyle = b;
  13:         _mouseOverItem = a;
  14:         if (_tabFocusedItem != "") {
  15:             ChangeReportItemStyle(_tabFocusedItem, _unselectedItemStyle);
  16:             _tabFocusedItem = ""
  17:         }
  18:         ChangeReportItemStyle(a, c)
  19:     }
  20: }
  21:  
  22: //this will stop the click event from displaying the dropdown
  23: function Clicked(b, l) {
  24:     var tagname = GetUnSelectedParentTagName(this);
  25:  
  26:     if (tagname == "DIV") {
  27:         return true;
  28:     }
  29:     else {
  30:         if (!_onLink) {
  31:             ClearTimeouts(); SelectContextMenuFromColletion(l);
  32:             _itemSelected = true;
  33:             if (b == null) b = window.event;
  34:             var i = b.target != null ? b.target : b.srcElement, a = GetOuterElementOfType(i, "table"), e = GetElementPosition(a); _selectedItemId = a.id;
  35:             _selectedIdHiddenField.value = a.value;
  36:             a.className = "msrs-SelectedItem";
  37:             ResetContextMenu();
  38:             var g = _divContextMenu.offsetHeight, h = _divContextMenu.offsetWidth, o = a.offsetHeight, p = a.offsetWidth, j = e.left, k = e.top, d = 0, c = 0;
  39:             if (typeof window.innerWidth == "number")
  40:             { d = window.innerWidth; c = window.innerHeight }
  41:             else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
  42:                 d = document.documentElement.clientWidth;
  43:                 c = document.documentElement.clientHeight
  44:             }
  45:             else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
  46:                 d = document.body.clientWidth; c = document.body.clientHeight
  47:             }
  48:             var f = document.compatMode && document.compatMode != "BackCompat" ? document.documentElement : document.body, m = document.all ? f.scrollLeft : pageXOffset, n = document.all ? f.scrollTop : pageYOffset; _divContextMenu.style.left = SetContextMenuHorizonatalPosition(d, m, j, h, p) + "px";
  49:             _divContextMenu.style.top = SetContextMenuVerticalPosition(c, n, k, g, o) + "px";
  50:             ChangeOpacityForElement(100, _divContextMenu.id);
  51:             document.getElementById(_currentContextMenuId).firstChild.focus()
  52:         }
  53:     }
  54: }
  55:  
  56: //gets tag name before the object with the specified class name.
  57: //i found that it's a DIV in tile view, and not when in details view, so it's the differentiator i use to see what view i'm in
  58: //i'm sure there are multiple ways to do this, and this way is brittle, but hey, it works for now.
  59: function GetUnSelectedParentTagName(obj) {
  60:     var tagname = "";
  61:     try {
  62:         var src = obj.event.srcElement;
  63:         while (src.className != "msrs-UnSelectedItem") {
  64:             src = src.parentNode;
  65:         }
  66:         tagname = src.parentNode.tagName;
  67:  
  68:     }
  69:     catch (e) {
  70:     }
  71:     return tagname;
  72: }

That’s it.  Basically I’m finding out whether we’re in tile or details view by seeing if our menu item is contained in a DIV (for tile view) or not.  If we are in a div, I just stop processing in the key functions.

ReportingServices.css

I only changed two styles in the stylesheet.  Here’s the old style:

   1: div.msrs-tileView { float: left; height: 70px; }
   2: a.msrs-itemName  { white-space: nowrap; width: 250px; overflow: hidden; text-overflow: ellipsis; color:#000000; }

And here’s the new:

   1: div.msrs-tileView { float: left; height:50px; }
   2: a.msrs-itemName  { width: 250px; text-overflow: ellipsis; color:#000000; }

Basically, I’m tightening up the whitespace by changing the height of each tile menu item, and then I’m stopping the style from hiding the overflow text, and letting the text wrap.

Summary

That’s it.  If you do this correctly, the changes will be reflected immediately after saving the css and js files and refreshing your tile view.