Civil Pro has a new home!

TLDR; go to https://www.civilpro.com

Since our humble beginnings last century (yes it has been that long), Civil Pro has been under continuous development with 10 major releases, and over 200 minor releases. 5 years ago in 2016 we released our mobile QA integration. Three years ago we started to work on our Cloud application, and for the last two years have been working on the biggest ever update, Version 11.  Both of these products are now in production.  

The focus of the latest versions has been to refine our paperless workflows and improve efficiencies in the contractor-client interface. We have hit recent milestones adding subcontractor access and contract notices to the Cloud app. We will be adding POs and Site Diary in Aug/Sep releases to provide 100% coverage of features from the old mobile app (as well as all the new Cloud features that are already there of course).

Many of you may be aware that in delivering the Cloud application we have been partnered with Australia and New Zealand’s Trimble distributors, Herga group (BuildingPoint, SITECH Construction Systems, UPG & Information Alignment). This has given us access to essential additional resources and defines the future direction of our application. You can see this in our development which sees us address key pinch points around collection of compliance data through equipment and machine integrations, and integrations with construction design models. 

Following the success of the partnership in the development of the Cloud application, we are pleased to announce that we have agreed to extend the relationship. The Civilpro desktop and Cloud applications will be serviced through a new company, Civilpro Software Pty Ltd. Check out the new website – www.civilpro.com. This new business is a joint partnership between Blue Sky Contracting and the Herga Group. 

For our customers, this essentially means additional resources for a rapidly evolving product focusing on efficiencies in the management of Quality Assurance. Our mission is to take Quality Assurance beyond paperless to effortless.This is a big target, but every step we take towards this goal saves time, resources, and costs on construction projects across the country.  Beyond the opportunities additional resources provide for the application, this also addresses the question I am often asked ‘what happens if you get hit by a bus?’ 

I will continue to be a key part of the team as a co-owner and managing director of this new business and will continue with the application development and strategy. Most of you have my number anyway, and I will continue to do my best to avoid buses. From my perspective, little will change except that I now get a hand! 

If you want to discuss our new features and/or migration to the new versions, please proceed to our new online presence at www.civilpro.com. Here you can find information on the new products, support for the new versions, and access to our Zendesk ticketing system. 

As always, thank you for your business and in supporting 100% Australian owned and operated companies. Boutique software development is not an easy gig, and we could not do it without your feedback and support. 

Autoversion your SPA index.html

The curse of the cache

If you are in an ongoing development stage with a mobile application, you will often come across issues with your customers browser cache. Even if everyone was aware that your site actually works and just needs a hard reset – it isnt always possible. Take for example an Android js/html app launched as a Homescreen App. It seems the only way to force these things to update all of their files is to empty the entire chrome cache.

This is especially a problem when you have a data driven app retrieving its data from something like an odata dataservice. You can update the data service (for example – add a parameter to a get service) and it works perfectly with your front end as the current version. Then someone with a cached version of the client app tries to access the service and it breaks. Not a good look.

On the other hand, the cache exists for a reason. It makes your application far more responsive and reduces the traffic significantly. So, while we want to maintain the cache, we want to flag to the browser when an individual file for the application has changed. If only there was a way…

Forcing a reload

Well, there is. You can add a version to each file retrieved from the server. If the file version number changes, then the browser will get the new version and not use the cache. The easiest way to do this is to specify the version as a query string. To force a refresh, change the version number.

Instead of

<script src=”views/LogOnPopup.js” type=”text/javascript”> </script>

Use

<script src=”views/LogOnPopup.js?v=3″ type=”text/javascript”> </script>

In the case of an SPA in pure JS/HTML, this is made relatively easy because all the files are identified in the index.html. This is the case I will deal with here. If you are dealing with dynamically generated pages using something like asp.net (or heaven forbid php), you will need more exotic solutions than presented here – things like rewrite rules etc. Beyond the scope.

There is a whole stack about this at http://stackoverflow.com/questions/118884/how-to-force-browser-to-reload-cached-css-js-files. A lot of reading, but it helped me figure out a neat solution.

Versioning your index.html

So, if you have a decent sized SPA, you don’t want to be manually versioning your files. It is a PITA, and you will inevitably stuff it up. One solution (as outlined here) is to automagically add the date each file was last modified as the query string as part of the deployment process.

The following code uses c# and HTML Agility Pack (get it from nuget) to parse an index.html file and save it as a new file. I wrote a little windows app that has a GUI – download it here

The guts of the code looks like this;


       private void ParseIndex(string inFile, string addPath, string outFile)
        {
            string path = Path.GetDirectoryName(inFile);
            HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
            document.Load(inFile);
            foreach (HtmlNode link in document.DocumentNode.Descendants("script"))
            {
                if (link.Attributes["src"]!=null)
                {
                    resetQueryString(path, addPath, link, "src");
                }
            }
            foreach (HtmlNode link in document.DocumentNode.Descendants("link"))
            {
                if (link.Attributes["href"] != null && link.Attributes["type"] != null)
                {
                    if (link.Attributes["type"].Value == "text/css" || link.Attributes["type"].Value == "text/html")
                    {
                        resetQueryString(path, addPath, link, "href");
                    }
                }
            }
            document.Save(outFile);
            MessageBox.Show("Your file has been processed.", "Autoversion complete");
        }

        private void resetQueryString(string path, string addPath, HtmlNode link, string attrType)
        {
            string currFileName = link.Attributes[attrType].Value;

            string uripath = currFileName;
            if (currFileName.Contains('?')) uripath = currFileName.Substring(0, currFileName.IndexOf('?'));
            string baseFile = Path.Combine(path, uripath);
            if (!File.Exists(baseFile)) baseFile = Path.Combine(addPath, uripath);
            if (!File.Exists(baseFile)) return;
            DateTime lastModified = System.IO.File.GetLastWriteTime(baseFile);
            link.Attributes[attrType].Value = uripath + "?v=" + lastModified.ToString("yyyyMMddhhmm");
        }

 

The addPath parameter is an additional root path to search for each file in the index on to get its modified date. This is because in my solution I have two projects that are compiled into one. The index.html assumes they are both in the current (which they are when compiled), but at development they are not.