Thursday, 13 July 2017

Report row buttons firing a dynamic action

A lot of the time on reports of data, we'll define a link column, and specify an image which is the beloved pencil icon.

Which is good and all, but looking in the Sample Database Application (packaged application), they have taken a different approach to style links - a button that stretches the width of it's containing cell. So, the UI ends up looking like so:

So, is this done?

Well first, you define a new column for the placeholder. Suppose I want my link column to be Report, I define an extra column in my query:

, 'Report' report_link

Then I need to go to my new column's attributes, and change the column type to a link.

And, in the link attributes, set the text to what you want displayed. Here, I'm just going to display the value of the new column and point to my desired page. So I set the target page, then also the Link text as #REPORT_LINK#.

At this point the report will just show link text, as we expect.

So, then to replicate the same style, we just need to apply the same classes, which happen to be:

  • t-Button 
  • t-Button--simple 
  • t-Button--hot 
  • t-Button--stretch
So, in the link, set the link attributes as:

class="t-Button t-Button--simple t-Button--hot t-Button--stretch".

Now when we run the page, we get the desired behaviour:

How about for a dynamic action?

Well, in the columns link, there is no option for "Defined by Dynamic Action" as we usually see in regular page buttons. We just get page or URL options.

Typically, you will assign a special class to your element so that you can specify a jQuery selector on your dynamic action target that will fire and optionally a data attribute used to store the ID of the row (such as data-order-id="xx"). More on this later.

So, back to the column action. A typical pattern here will be to specify URL and that a target of #, javascript:void(0);, or javascript:;.

The # is usually a trick when you want to go to a position in the same page, so not using href as it was designed for.

The void is a JavaScript operator that returns void, and the other one is obviously an empty javascript expression!

When using void, it is important to pass in 0 to the function, or it's likely you will receive the following error:

Uncaught SyntaxError: Unexpected token )

With all that said, I think it is better to avoid these (hacky?) solutions. It is not a "link" so the href tag should ideally not be there. If you want a row button that will fire a dynamic action, instead you should set the column type to plain text and then set a HTML expression on the column.

Since it is a button we want, it is a button we shall use. We will end up with markup as follows,  that we add into the HTML expression:

<button class="orderReportButton
           t-Button--stretch" data-order-id="#ORDER_ID#" type="button">
    <span class="t-Button-label">Report</span>

There we have.

Now, we just need to finish off our dynamic action. We create a click dynamic action based on a jQuery selector.

Then, in our true action, we can just reference the expression "this.triggeringElement.getAttribute('data-order-id')" or jQuery "$(this.triggeringElement).data('order-id');

Monday, 10 July 2017

Custom workflow to download or upload specific Google Drive files

I had an interest in downloading and uploading a specific file into my Google Drive at certain timing points. For examples sake, let's call the files "Designs.cad". There is a command line project on GitHub which is Go based. So if you have Go installed, it is just a matter of running:

go get

This will download from source, so if you don't want to do this or if you don't have Go installed (you should - there are lots of great go projects), you can see a list of releases on the project page - - which you can download and place in your system somewhere, with the command becoming "gdrive".

When you first install it, you will need to authenticate your account. Running any command will prompt you to go to a URL to get an authorization code and paste in back on your console. So for example, if I run:

gdrive list

Which is designed to list files in my Drive. After running the command, if you haven't previsouly authenticated, you will be prompted to go to a URL to paste the authorization code. Sample output:

trent@birroth:~$ gdrive list
Authentication needed
Go to the following url in your browser:

Enter verification code: xxx

Where xxx is the verification code I pasted back in.
If successful, you will end up with a file at: $HOME/.gdrive/token_v2.json, containing on the necessary authorization codes so the program can continue to function whilst ever the authorization exists for this application.

So, looking at the help, there are two commands that will be useful - download and update.

We can find out the program usage with the help command, like so for the download operation.

$ gdrive help download
Download file or directory
gdrive [global] download [options] 

  -c, --config          Application path, default: /home/trent/.gdrive
  --refresh-token       Oauth refresh token...
  --access-token        Oauth access token...
  --service-account     Oauth service account filename...

  -f, --force           Overwrite existing file
  -s, --skip            Skip existing files
  -r, --recursive       Download directory recursively...
  --path                Download path
  --delete              Delete remote file when download is successful
  --no-progress         Hide progress
  --stdout              Write file content to stdout
  --timeout             Set timeout in seconds...

To use this, I need to find the file ID, which I can do by using the list command, or looking at the web interface of Google Drive. The filename will be the same as that as it is on Google Drive. So, with that information I end up with the command:

gdrive download --path /home/trent/ --force 1GUG3Y3Ce56Pa0k2

Which gives output like so:

Downloading Designs.cad -> /home/trent/Designs.cad
Downloaded 1GUG3Y3Ce56Pa0k2 at 18.2 KB/s, total 18.2 KB

Similarly, to send the file in the other direction, we need to look at the usage for the command update

$ gdrive help update
Update file, this creates a new revision of the file
gdrive [global] update [options]  

  -c, --config           Application path, default: /home/trent/.gdrive
  --refresh-token        Oauth refresh token...
  --access-token         Oauth access token...
  --service-account      Oauth service account filename...

  -p, --parent           Parent id...
  --name                 Filename
  --description          File description
  --no-progress          Hide progress
  --mime                 Force mime type
  --timeout              Set timeout in seconds...
  --chunksize            Set chunk size in bytes...

That means, our command will become:

gdrive update 1GUG3Y3Ce56Pa0k2 /home/trent/Designs.cad

Sunday, 9 July 2017

Converting a physical machine for use in VirtualBox

I recently had an interest in converting a physical machine (Windows) I have into a virtualised environment. For my personal Virtual needs, I tend to use and favour VirtualBox - so my end goal is to have the system running in VirtualBox.

A quick google with these keywords reveals this VirtualBox article: However, this talks about Windows XP, and then one of the software it references is 10 years old. And for some extra context, Windows XP was first released in 2001 and the last release (SP3) in 2008. Ok, so I'm deciding not to go down that path.

Putting aside the previous article, I happen to know there are two solutions that support converting a physical machine.
  • VMWare
  • Microsoft (Disk2vhd)
So, I will go with the VMWare option for this article/guide. The software is found over at: So, I download and install the software (note, you will need a VMWare account in order to download this software).

The software includes official documentation in the form of a PDF document, so if you want to review that, head over to: - chapter 6 is the relevant chapter.

Firstly, you will want to start the program as Administrator to ensure you have full privileges. Search for VMWare and right click the relevant entry, and then click "Run as administrator".  Once it's opened, click on the "Convert machine" toolbar button - this will begin the wizard.

For the source, it's pretty safe to leave the default options

On the second step, Destination system, I will opt to target VMWare Player 7.x. And I think it goes without saying you should be targeting this to be saved on an external disk. So, the desitnation configuration ends up looking like:

After this step, you will be presented with all the system options that you may want to update - such as reducing the memory, since your virtual environment would probably have far less memory than your physical machine. I also change the number of virtual cores down to 2 (from 4).

That's all done we can run the conversion. Click Finish and the process will begin. After the job submits, the process will take some time, so you can re-visit the process later (it offers a time estimation - for me, it estimated 1 hour, but jumped up and down periodically).

In the meantime, we can go and grab VMWare Workstation player, if we don't already have anything to verify the conversion in VMWare. This can be found here: note: this is free for non-commercial use. This is just if you want to verify the conversion in VMWare - if you prefer, or that license doesn't suit, you can skip this step and grab the ovftool directly over here:

With the conversion finished, you should end up with two files: a vmdk and vmx file. Here, we can test it works by opening it up in VMWare Player - for performance, you may want to copy the files over to your host computer, space permitting. Aside from that, all should be working.

Now to convert this for use in VirtualBox. You can either just point at the vmdk file and create the machine manually or create an appliance - I will go forward with the latter approach, though pointing at the existing storage file (vmdk) will get you up and running much quicker!

VMWare player comes with a command line program named ovftool which supports converting from "VMX" to "OVF". (This tool can also be downloaded standalone: - the next step is based on if you installed VMWare player). So, go to the folder where workstation player was installed to - on my system, it is: "C:\Program Files (x86)\VMware\VMware Player". You should see a folder named "OVFTool" - right click that whilst holding the shift key, and click "Open PowerShell Window Here".

Then run (adjusting to where your VMWare VM was saved to and where you want the VirtualBox appliance saved to) the following:

ovftool.exe "F:\VMWareConverted\WindowsVM\WindowsVM.vmx" "F:\VBAppliance\WindowsVM.ovf"

This is another fairly long process, so sit back!

Once that finishes, head over to VirtualBox, and import the appliance we just created - the ovf file.

The name comes through as "vm" so you'll probably want to update that, I also changed the Guest OS Type property to Windows to match my system.

I also disabled all the network adapters (4) that came through in the settings, so I can manually add them later - I encountered issues where the network adapters weren't being detected properly in the guest, so this is probably the safer option - we add the network interfaces manually after import.

Click import to create the VM within VirtualBox.

Once that finishes, when attempting to run the machine, you will find you're not out of the woods yet. So, here are some extra steps you'll want to do before starting the virtual machine.

  • Enable EFI (if your computer is recent and EFI based)
  • Move the HDD to the SATA controller 
  • Add an optical disk (so we can install the guest additions)
  • Enable the network
  • Switch to Intel HD Audio
  • Install guest additions

I found that when starting the system, I would receive the following error:

Enable EFI

After doing a bit of digging, I can see in the VirtualBox settings, EFI is not enabled but my system is fairly recent so that is in use and needs to be enabled. So head into the configuration and make sure that is enabled.

So, now this time when trying to boot we will get another error. Progress!

Move the HDD to the SATA controller 

Looking in the VM configuration, I see the storage device is attached to a SAS controller. Just on a hunch, I try moving the moving the device into the SATA controller (delete and re-add the disk from the storage sections in the machine settings).

So, remove the disk "WindowsVM-disk1.vmdk" from the SAS controller

Then re-attach it to the SATA controller. When prompted, specify Choose existing disk and navigate to where the disk is stored. This will a path similar to be: $HOME/VirtualBox VMs/ConvertedPC/WindowsVM-disk1.vmldk.

Add an optical disk

In the same settings area (Storage), click on the optical disk icon that is on the same line as the controller, in order to attach an optical drive to the system.

When prompted, specify to leave empty.

Add a network interface

Since we disabled all network interfaces when importing the appliance, head over to network settings and add a NAT adapter so you can access the internet.

Switch to Intel HD Audio

When I first booted, I found the audio controller wasn't working so I switched it over to Intel HD Audio, and all worked well after that.

And after doing all this, we are able to successfully boot into our PC that has now been virtualised.

Install guest additions

Log in, and install guest additions. This is done by clicking on the Devices menu and selecting Insert Guest Additions CD image...

Follow the steps in the VM. After the process completes it will want to reboot your system - after which point you have your fully functional converted PC as a VM in VirtualBox.

edit: If you have input issues due to hardware differences, this thread will help: - you need to modify some registry entries