Modern Software Development Lifecycle – Part 2 Continuous Integration

This post is part 2 in a three-part series of posts on Software Development Lifecycle in the “Modern” development paradigm. As I explained in the previous post, I have been thinking about how to integrate client-side code into enterprise development processes. Many years ago, I was introduced to a concept called continuous integration. I even implemented it at a previous employer, it was awesome. Continuous integration is the concept that as changes are made to code they can immediately be combined and tested to make sure everything works. Then once everything checks out continuous integration tools can also handle the deployments for us. As my development has shifted from compiled code to more client-side code, I have been trying to figure out how to use the tools and processes that I have been using with client-side methodologies. I recently figured out how integrate continuous integration into my processes now. This revelation was thanks in part to the push of the SharePoint Framework. I also recently came across the fact the Visual Studio Team Services has added continuous integration capability. TFS supposedly has this feature as well. In order for this to work with our processes in SharePoint and JavaScript you will need to have a working gulp script from the previous part for these instructions to work.

Continue reading “Modern Software Development Lifecycle – Part 2 Continuous Integration”

Manually Registering a SharePoint Add-In

After writing the Modern Development Lifecycle article I came to the realization that the article I mentioned for creating the client id and secret missed an important step. It missed how to create the application itself. So in this article we are going to create and permission an add-in so it is ready for our use. Continue reading “Manually Registering a SharePoint Add-In”

SharePoint Framework Release Candidate 0

In big news on the SharePoint development front, the SharePoint Framework reached release candidate 0 yesterday. What does this mean? Release candidate means that what we are seeing now in the SharePoint Framework is pretty close to what it’s going to look when it reaches general availability(GA). In looking through the release notes associated with this release, https://github.com/SharePoint/sp-dev-docs/wiki/Release-Notes-RC0, there are quite a few changes. Some of the changes are pretty major and will break any existing web parts that you may have created. So why would Microsoft do this? The reason is to perform some final cleanup of things that did not exist as they should in a polished project. They had to rename and move quite a few things. If Microsoft did not do this now it would probably not happen and there would be areas of conflict and confusion. You can tell the scope of how many different areas have changed by the update steps that are included in the release. Previous releases had a couple things that needed to be updated, while this release has 12 different steps of things that need to be updated. If you are doing SharePoint Framework development I highly suggest that you look through the release notes. The release notes will guide you through all the changes and Microsoft’s direction and thinking about the changes. Some of the most notable changes are:

Continue reading “SharePoint Framework Release Candidate 0”

Modern Software Development Life Cycle Part 1

I have been doing JavaScript development for many years now but it was always included as part of some other server side code that was easy to manage. When I started working on Office365 and doing 100% client side code I have struggled with the best way to manage the artifacts that are being created. With server-side code we just used Visual Studio and that would handle our connection to version control and a plethora of other tools to help us write better code. When things changed to working in Office365 I started out by adding the artifacts to a library in SharePoint and then editing them with SharePoint Designer. I know, I know, SharePoint Designer is not a good code editor but in regards to save performance, SharePoint Designer behaves better than anything else out there. The problem with this is that the code that I am creating is not stored in a centralized source repository. Also, if I wanted to get the code into the repository it was a manual effort to copy the files back to my machine and then check everything in. Dealing with multiple developers working on a project could be rather tricky since we were working on the exact same files. There have been times were changes have been temporarily lost due to a save that did not include the changes from other developers. Because of this I always make sure the library I am using has versioning turned on and sometimes I’ll require checkout depending on the likelihood of multiple devs working on the same files. Another problem with this approach is that there is no way to run any code improvement processes. If I want to use TypeScript for example, your code has to be on a local drive for the TypeScript compiler to do its thing. If you try to run it on a mapped drive through WebDav, TypeScript complains. There are also code tests, bundling, and minification that are tricky to run directly from a SharePoint library. With the introduction of the SharePoint Framework I have realized that I needed to figure out how to best handle the client-side pieces in regards to the Software Development Life cycle. This series of blog posts will cover those topics.

Continue reading “Modern Software Development Life Cycle Part 1”

To TypeScript or Not to TypeScript

Many times, when I go speak on modern development, I get asked the same question, “Do I have to use TypeScript?” So I figured I would answer this through a blog post so I can make sure I answer all the pieces to this question. If you haven’t used TypeScript before I’ll cover what TypeScript is and provide the information so you can decide whether you want to use TypeScript in your projects. Continue reading “To TypeScript or Not to TypeScript”

Using Workflows to Perform Elevated Actions

Problem

When making the move to the cloud one of the biggest challenges for developers is how to accomplish tasks that used to be fairly simple. Recently I came across one of these instances. I had a client that we had setup in Office365 over a year ago and since that time several applications have been created. One of these applications was a time off request form. When this was setup it wasn’t brought up that they wanted to limit who could see the requests. We setup a solution where we broke the inheritance of the request after it was created. We only had an admin level account so full testing didn’t happen in this instance. We released the update and apparently it was communicated to another developer that it wasn’t working and instead of fixing the problem they just commented out the permissions section.

Continue reading “Using Workflows to Perform Elevated Actions”

Announcing Release of AngularSP to Beta

I am announcing the initial release of my first open source project, AngularSP. I have been working more and more with AngularJS and I love it. AngularJS has saved me so much development time. The problem I saw was that every project I worked on, I had to embed/re-create the connections with the SharePoint REST services. I kept thinking, I really should just do a service similar to $http to encapsulate the functionality. So here is the initial release of the factory. Currently the library handles all of the CRUD operations on SharePoint lists hosted within the same domain as the calling page(no cross site calls as of right now, that will come later). The library will work with On-Premise SharePoint as well as SharePoint Online in Office 365. The plan is to add more functionality as time goes on.

The current priorities are listed on the CodeProject site but I am including them here as well for now.

  1. Automatic handling of Request Digest Token for REST Implemented
  2. Search Calls
  3. All implemented methods for the request executor.

Let me know if there are any features that you would like to see added.

AngularSP on CodePlex

SharePoint 2013 Add To Timeline Programmatically

With the release of SharePoint 2013 Microsoft added a couple new web parts that users may have seen but may not have realized that they can use them in their own pages. The two web parts are related and one includes the other. These web parts are the Project Summary Web Part and the Timeline. There have been several blog articles talking about these web parts so I am not going to go into too much detail but the part I will cover is the fact that both these can be used on your own web part pages.

Project Summary Web Part

ProjectSummary

 

The beauty of this web part is its ability to be able to give your users a quick at the status of the tasks within your site. In the top of this web part you can see an option to add a task and edit the list which will both allow you to interact with the list. There is also a scroll arrow which will take you to the a view of the next web part.

Timeline Web Part

TimelineScreenShot

 

The timeline web part is also made available as a user control that you can embed in your own web parts but it is a little tricky to figure out how to make it work, more on how to do that in another post. the Timeline web part is the section in the right portion of the screenshot. What the screen shot does not allow you to see is the fact that you can click and drag the tasks to different places to make it more legible. You can also change the styling and colors of the timeline through the ribbon. Both of these changes are persisted so when you come back later your changes will still be there.

This is cool but can I work with it programmatically?

Both of these web parts are tied to a task list in your site. So to add a task to your timeline it is easy to do from the task list. The menu for the task gives you an option to add to timeline. All this is cool but how do I work with the these web parts? I have searched high and low to figure out how to be able to manipulate the what tasks are shown on the timeline and I couldn’t find anything. So being a developer I decided that if Microsoft can do it in their own web parts then I should be able to do so myself. I found several blogs that mention a programmatic way of adding tasks to a timeline. The task data that is used to generate the timeline is stored as  a property on the root folder on the list called “Timeline_Timeline”. If you look at the value of this property you can see that it is just XML. Easy enough to work with right? This felt like a hack to me so I kept digging.

In my digging I found out that Microsoft added a JavaScript file called sp.ui.timeline.js to the SharePoint page whenever the timeline control is loaded. So I decided to go look at that file and see if I could find a way to add tasks without it being as much of a hack. The sp.ui.timeline.js file is located in the layouts folder under the SharePoint Root. The cool thing is that most of the SharePoint JavaScript files include a debug version that has not been minified. This makes it easier to read, not easy just easier. A lot of the functionality has gone through some sort of obfuscation but you can get some basics.

In digging through the debug file I found that Microsoft exposed a couple methods in the root(window) namespace. These methods are

  • AddItemsToTimeline
  • RemoveItemsFromTimeline

The parameters for both methods are the same. The parameters are included below in order:

  1. items – The items parameter was a tricky one to figure out. I tried a couple variations before I dug some more in the file. It turns out that it expects an array of objects and those objects need to have an id property.
  2. ListID – This is fairly self explanatory except that you need to make sure it is lower case without the curly braces.
  3. ViewName – The ViewName is always the same. The view is “Timeline”

Now with this information it is fairly easy to be able to setup a method to add a remove tasks from the timeline

function AddNewTaskToTimeline(itemID, listId){
    AddItemsToTimeline([{ 'id': itemID }], listId, 'Timeline');
}
function RemoveTaskFromTimeline(itemID, listId) {
    RemoveItemsFromTimeline([{ 'id': itemID }], listId, 'Timeline');
}

These functions could easily be placed as part of your own classes.

So we can add and remove tasks what next?

Now that we can add and remove the tasks on the timeline what is left for us to do? Oh, that’s right this is an enterprise system and we need to provide the user with proper feedback so that we can show them the proper text. Add when they want to add and remove when the task is already on the timeline. This one required some more noodling. I looked all over the JavaScript objects that are created as part of the sp.ui.timeline.js file and I found several places that contain the data that is on the timeline so I thought sweet I can just use those right? Wrong. You can see the items on the timeline but the script from Microsoft does not update these objects when the methods to add and remove are called. The out of the box functionality has the same limitation so I knew it wasn’t that I was adding them wrong. I tried reloading the page after adding but if you reloaded too quickly the add/remove didn’t happen.

After quite a bit of puzzling until my puzzler was sore I came up with an idea. A wonderfully awful idea. I realized that the information I needed was on the server so I thought I could write a service that would get me the data and verify if the task is on the timeline. As I started prepping for this route the SharePoint Developer in me said, “You don’t need to write your own service. Try the out of the box services.” So I did. It turns out that it requires a couple JSOM calls to get to the data I needed but the data is indeed available.

The first step is to load the list from the server. This is a fairly simple JSOM task so that one wasn’t too tricky.

function LoadList() {
    var ctx1 = SP.ClientContext.get_current();
    List = ctx1.get_web().get_lists().getByTitle(ListName);
    ctx1.load(List, "Title");
    ctx1.executeQueryAsync(LoadListCallback, QueryFailed);
}

I snag the list on page load after client context is loaded. I then hold on to this as a variable in my class so that I can use it for the second part.

The list didn’t have the value I needed so I had to go one step further. In looking at the approaches mentioned previously I realized that the data that I wanted is part of the Root Folder of the list. So I had to make another call to SharePoint to get the root folder.

IsTaskOnTimeline: function (taskId, Callout) {
    checkingId = taskId;
    callout = Callout;
    var ctx1 = SP.ClientContext.get_current();
    properties = List.get_rootFolder().get_properties();
    ctx1.load(properties);
    ctx1.executeQueryAsync(CheckTaskCallback, QueryFailed);
}

In my implementation I was  showing the option as part of a callout, another cool piece of functionality that was added in SharePoint 2013. I take the context and the list and go get the root folder  and its properties. Once I have this information in the callback I can now check if the task in question is on the timeline and update the action on the callout accordingly. This method, IstTaskOnTimeline is called every time that the callout is rendered thus making sure it is up to date. Thanks to jQuery parsing since the data is stored as XML it makes it easy to query the XML to see if the task I am looking for is on the timeline. The data comes back as some pretty ugly all on one line XML. But here it is formatted to make it easier to work with.

<TLViewData>
	<fmtSet>
		<fmt id="0" clr="FFEE2222" thm="0001" t1="0" t2="1" type="0" />
		<fmt id="1" clr="FFEE2222" thm="0001" t1="2" t2="3" type="1" />
		<fmt id="2" clr="FFEE2222" thm="0001" t1="4" t2="5" type="2" />
		<fmt id="3" clr="FFEE2222" thm="0001" t1="6" t2="7" type="3" />
	</fmtSet>
	<fltSet>
		<ft id="{00000000-0000-0000-0000-000000000000}" uid="4294967295" uidSrc="1" onTL="0" fmt="1" y="4294967282" x="0" h="20" />
	</fltSet>
	<tskSet>
		<t id="{00000000-0000-0000-0000-000000000000}" uid="4294967295" uidSrc="1" onTL="0" fmt="0" ch="4294967295" />
		<t id="{D8B18823-A736-4A9A-A804-0BD23BF1552D}" uid="23" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
		<t id="{52B9A142-C89C-40DC-83C8-33A00CF03B6C}" uid="26" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
		<t id="{E89E7256-F104-4AA9-BC53-13439E0EAA42}" uid="25" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
		<t id="{B6074014-2A71-45D5-BBAF-FB0DA2A201A1}" uid="24" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
		<t id="{C5789532-D420-4C9B-B704-D5CDEA3350EF}" uid="22" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
		<t id="{EFC756A8-1B16-495C-AB7D-112B31A59534}" uid="21" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
		<t id="{990078A6-BF87-4121-A720-ACFB1685A8B2}" uid="79" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
		<t id="{2FFCFA8C-7CD1-429F-BDA6-E6BB4BC3A71C}" uid="80" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
		<t id="{2D77DD43-A9F6-4B1D-8E6C-12474F3E3CFB}" uid="82" uidSrc="1" onTL="1" fmt="0" ch="4294967295" />
	</tskSet>
	<options dateFormat="3" panZoomT="9" ProjSummFmt="3" showDates="1" showProjSummDates="1" showToday="1" showTS="1" timelineHeight="110" timelineWidth="-1" timescaleT="8" todayT="10" />
	<mlSet>
		<m id="{00000000-0000-0000-0000-000000000000}" uid="4294967295" uidSrc="1" onTL="0" fmt="2" y="35" x="0" />
		<m id="{D8B18823-A736-4A9A-A804-0BD23BF1552D}" uid="23" uidSrc="1" onTL="1" fmt="2" y="17" x="60" />
		<m id="{52B9A142-C89C-40DC-83C8-33A00CF03B6C}" uid="26" uidSrc="1" onTL="1" fmt="2" y="5" x="49" />
		<m id="{E89E7256-F104-4AA9-BC53-13439E0EAA42}" uid="25" uidSrc="1" onTL="1" fmt="2" y="4294967273" x="4294967249" top="1" />
		<m id="{B6074014-2A71-45D5-BBAF-FB0DA2A201A1}" uid="24" uidSrc="1" onTL="1" fmt="2" y="4294967262" x="0" top="1" />
		<m id="{C5789532-D420-4C9B-B704-D5CDEA3350EF}" uid="22" uidSrc="1" onTL="1" fmt="2" y="4294967263" x="0" top="1" />
		<m id="{EFC756A8-1B16-495C-AB7D-112B31A59534}" uid="21" uidSrc="1" onTL="1" fmt="2" y="13" x="33" />
		<m id="{990078A6-BF87-4121-A720-ACFB1685A8B2}" uid="79" uidSrc="1" onTL="1" fmt="2" y="35" x="0" />
		<m id="{2FFCFA8C-7CD1-429F-BDA6-E6BB4BC3A71C}" uid="80" uidSrc="1" onTL="1" fmt="2" y="35" x="0" />
		<m id="{2D77DD43-A9F6-4B1D-8E6C-12474F3E3CFB}" uid="82" uidSrc="1" onTL="1" fmt="2" y="25" x="4294967020" />
	</mlSet>
	<txtSet>
		<style id="0" type="0" clr="FFEE2222" thm="0001" sz="8" font="Segoe UI" bold="0" ital="0" und="0" strk="0" />
		<style id="1" type="1" clr="FFEE2222" thm="0001" sz="8" font="Segoe UI" bold="0" ital="0" und="0" strk="0" />
		<style id="2" type="2" clr="FF999999" thm="0001" sz="8" font="Segoe UI" bold="0" ital="0" und="0" strk="0" />
		<style id="3" type="3" clr="FFB3B3B3" thm="0001" sz="8" font="Segoe UI Light" bold="0" ital="0" und="0" strk="0" />
		<style id="4" type="4" clr="FF525051" thm="0001" sz="10" font="Segoe UI" bold="0" ital="0" und="0" strk="0" />
		<style id="5" type="5" clr="FFB3B3B3" thm="0001" sz="8" font="Segoe UI Light" bold="0" ital="0" und="0" strk="0" />
		<style id="6" type="6" clr="FF999999" thm="0001" sz="9" font="Segoe UI" bold="0" ital="0" und="0" strk="0" />
		<style id="7" type="7" clr="FF999999" thm="0001" sz="8" font="Segoe UI" bold="0" ital="0" und="0" strk="0" />
		<style id="8" type="8" clr="FF999999" thm="0001" sz="8" font="Segoe UI" bold="0" ital="0" und="0" strk="0" />
		<style id="9" type="9" clr="FFFFA614" thm="0001" sz="8" font="Segoe UI Semibold" bold="1" ital="0" und="0" strk="0" />
		<style id="10" type="10" clr="FFFFA72B" thm="0001" sz="10" font="Segoe UI Semibold" bold="0" ital="0" und="0" strk="0" />
	</txtSet>
</TLViewData>

If you look at this XML you can see there is a lot going on. This is where all the position and formatting for the tasks is stored. The part that we care about is under the tskSet node. This node contains all the tasks that have ever been on the timeline on the list. This is important to keep in mind. If you remove a task from the timeline this task will remain in the tskSet node. Luckily it is easy to identify which tasks are on the timeline and which are not by the onTL attribute. Also on the t nodes there is a uid attribute. This is the item ID from the list item. So now that we have this information we can use jQuery to search the xml for us and tell us whether the task is on the timeline or not. Since jQuery parses HTML and for the most part now days HTML is XML, or really XML can be parsed like HTML and jQuery doesn’t care.

Here is out jQuery statement that will check for our task.

jQuery(properties.get_item("Timeline_Timeline")).find("t[uid='" + checkingId + "'][onTL='1']").length == 1

All we are doing is loading the XML into the jQuery parser then we call find on the jQuery object that represents our XML. We then call the find method and pass in selectors that will limit the objects returned to the one we care about. We are looking for all t nodes that have an attribute of uid that equals the id we are checking and an attribute called onTL with a value of one. If this returns any elemens, length greater than zero then the task is on the timeline. So we update the callout to display the appropriate value of Add or Remove. Then when the action is clicked on in the callout we call the appropriate add or remove function.

To me this is a much more elegant solution than changing the XML from the server or client. I’ll let Microsoft deal with their data the way they like. The beauty of this solution as well is that it will work with an on-premise SharePoint installation and it will also work if you want to use it in Office 365 or SharePoint Online.

Please let me know if you have any thoughts or questions.

 

 

Getting SharePoint List Version Setting for all lists

I was working at a client doing a health assessment and during the assessment we talked about problems with users being able to turn on versioning. That being that each time a modification is made it keeps a copy of that file and if versioning is turned on then this can drastically increase your content database sizes pretty quickly. I setup this script to be able to help identify what the settings are. This script could be modified to enforce a policy on what the limits should be as well.

Continue reading “Getting SharePoint List Version Setting for all lists”

Project Server Recycle Bin

I found it strange the Project Server does not have a recycle bin for cases of accidental deletion of a project. One of my clients also found this strange and so I setup a project recycle bin. It works fairly simply by taking advantage of the archiving system of project server. This worked pretty well except that there is no way to specify how long a project will stay in the archive. So I figured the simplest way of accomplishing this was to setup a timer job that will access all of the projects in the archive and check for the custom description set when the project is sent to the “Recycle Bin”. It would then check when the project was deleted to see if it needed to be flushed from the archive. So far so good. Project server provides a method for programmatically deleting a project from the archive. The documentation seems fairly clear, it can be found at http://msdn.microsoft.com/en-us/library/office/gg204474.aspx. So I had my timer job call this method on the projects that needed to be removed. The documentation says to call the function passing the following parameters in this order:

  1. Guid JobUID
  2. Guid ProjectUID
  3. Guid ArchiveUID

So I used the following line of code.

archiveSvc.QueueDeleteArchivedProject(JobId, project.PROJ_UID, project.PROJ_VERSION_UID);

Well when ever the job ran nothing was getting removed. I pulled my hair out trying to figure out why this wasn’t working. Then I had an epiphany, maybe the parameters are reversed. So I created a test console app where I could try changing the values around. What I found was that if I reversed that last two parameters the project gets deleted as expected. So I changed the code in my timer job to:

archiveSvc.QueueDeleteArchivedProject(JobId, project.PROJ_VERSION_UID, project.PROJ_UID);

Now everything works as expected. So what happens is that you are passing the VersionID as the project ID and the Project ID as the Archive ID. Go figure.