OneDrive for Business Sync App – Sync Issues Guide

OneDrive-LogoI’ll be the first one to admit that I’ve had massive problems with syncing in both OneDrive for Business and OneDrive (Personal). (The branding on this drive me nuts, too, but that’s a different post.)

Yesterday I learned of a page on the Microsoft site that takes you through problem-solving steps to fix (hopefully) your sync issues with OneDrive for Business. I’ve heard from Microsoft that “The highest priority is sync reliability and performance. We need to get this right.” Until they get some of the issues sorted, this trouble-shooting guide may well get you out of the woods.

I ran through the trouble-shooting steps yesterday, which led me to perform all of the steps through “Stop and re-sync your libraries”. Once I’d done that, I saw the glorious green check mark in the image below. I didn’t even know that check mark existed! I’d been stuck with over 500 “sync issues” for months.

2014-10-16_21-37-10

I think we should publicize the crap out of that link. While few people should really have to need these steps, they help to solve issues with OneDrive for Business.

Another thing I learned about is how to find out what version of the OneDrive for Business sync client you are running. In case you didn’t know, it’s actually the old Groove client running under the covers. In some cases, automatic updating of the client has been stuck. See the knowledge base article Some versions of the OneDrive desktop app for Windows do not update automatically (KB2990967) for details.

If you want to figure out what your current version of the sync client is, follow these steps:

For OneDrive for Business the sync client filename is groove.exe. Search for this file on your PC.
If you installed Office through an MSI the groove.exe file typically resides in\Program Files\Microsoft Office\Office15
If you installed Office or the sync client standalone through click-to-run then groove.exe typically resides in \Program Files\Microsoft Office 15\root\Office15

My Groove.exe file is in the latter location:

Groove.exe

Right click on the Groove.exe, go to Properties, and you’ll see the current version under the Details tab:

Groove.exe version

My version is 15.0.4659.1000 as of this writing, as shown above, because I’ve just updated to the most recent version. You can always check for the latest version of Office on the Microsoft Office 2013 Click-to-Run virtualization page. It will explicitly state in the page “The most recent Click-to-Run release is version 15.X.XXXX.XXXX”.

If you’re running an old version of the sync client and you’re able to do an update, you’ll be in better shape, as improvements are rolling out regularly.

I see great promise for OneDrive (both flavors) as they become more and more integrated into the whole Office story. As my friend Jeff Shuey (@jshuey) is always saying “I want to believe!” Keeping up with the updates for OneDrive can help make that promise a reality.

Requesting Your SharePoint “UI Hacks”

I am putting together a presentation talking about UI hacks that we all need to do in order to accomplish everyday UI customizations that our customers – internal  or external – require. For this one I want to limit it to SharePoint 2013 and/or SharePoint Online (Office365). Another way to think of it is how and why we brand SharePoint today on premises and in the cloud; not just things that people want cosmetically, necessarily, but stuff that is hard to do and must be done.

I’d like to collect ideas from all of you out there, which I will collate into some slides (with credit given, of course!). I posted a quick tweet about this and already got a few replies, so I figured a blog post would be a good way to gather information as well.

In thinking about this, I’ve come up with some broad buckets:

  • Inconsistencies
  • Documentation Gaps
  • Document Object Model (DOM) Changes
  • Missing Functionality (Oft Requested)

I’ve already got a few items of my own in each of those categories, but I’d like the presentation to be representative of what we all have to deal with, not just me. If you think I’m missing a bucket, let me know your ideas on that, too.

Let’s use this post’s comments to capture as much as possible. If you’d rather email me directly, you can use the Contact form. When I have a decent amount of content collected, I’ll come up with a way to share it on some level. (The actual purpose of this is classified.)

Thanks for your help on this.

SharePoint’s “Working on it…” In Any Language

It’s the message SharePoint gives us that we’ve learned to love or hate or be indifferent to. But it’s a message that we cannot escape if we use SharePoint even a little bit. Yes, I’m talking about “Working on it…”

Working on it EN-US

When I was in Stockholm this week speaking at the SharePoint and Exchange Forum (SEF), I noticed that the Swedish version of “Working on it…” was “Snart klart…”. According to my pal Christian Ståhl (@CStahl) at Humandata in Stockholm (the fine folks who put on SEF),

About ’Snart klart…’ this is strange translation, it’s more like ‘something will be finished soon‘ (maybe not always clear what) more than SharePoint actually doing something. Snart klart.. is more ok as an short answer to the kids that asks if the dinner will be served soon. Working on it.. is much better in a Swedish ear :)

That gave me a grin – I’m going to say “snart klart” when The Dude gets impatient with me about dinner from now on – and got me to thinking about what the message was in other languages. As with many idioms, the wording may be different and it may translate oddly as well. If you are using SharePoint with a language that I haven’t listed here yet, send me a screenshot of the message and a translation. I’ll post it here for everyone’s enjoyment and education.

Dutch

Working on it DUGoogle translate: “Processing…”

Submitted by Elio Struyf (@eliostruyf)

French

Working on it FR-frGoogle translate: “We soon finished…”

Submitted by Patrick Guimonet (@patricg)

German

Working on it DEGoogle translate: “Is in working… This should not take long.”

Submitted by Stefan Bauer (@StfBauer)

Swedish

Snart klart…

Google translate: “Almost there…”

Turkish

Working on it TUGoogle translate: “They are working on…”

Submitted by Gokan Ozcifci (@GokanOzcifci).

Caching SharePoint Data Locally with SPServices and HTML5’s Web Storage

The SharePoint SOAP Web Services are fast. In fact, I think they are as fast as the newer REST Web Services in many cases. The old, crufty SOAP Web Services even provide batching, something that the REST services don’t yet do. (Andrew Connell (@andrewconnell) has been beating the drum about this with Microsoft for months now, and we all hope they get this OData capability into SharePoint’s REST services sooner rather than later.)

Even though the SOAP services are fast, sometimes they just aren’t fast enough. In some of those cases, it may make sense to store some of your data in the browser’s Web storage so that it’s there on the client during a session or across sessions. Web storage is an HTML5 capability that is available in virtually all browsers these days, even Internet Explorer 8.

The best candidates for this type of storage (IMO) are list contents that are used as references and that don’t have a high number of changes. As an example, you might decide to store a list of countries in Web storage rather than loading them from the Countries list every time a page loads. Even though the read from the list is fast, it has to take *some* time. There’s the retrieval time, and then there is also any processing time on the client side. For instance, if you have dozens of fields per country and you need to load them into a complex JavaScript structure, that takes time, too. If those data chores are making your page loads seem laggy, then consider using local storage.

There are three main ways you can store data locally to improve performance. I’m not going to go into all of their intricacies, but I will give you some rules of thumb. There are a lot of nuances to this, so before you dive in, do some studying about how it all works.

Cookies

For small pieces of data, you should consider using cookies. Contrary to just about every article out there in the press, cookies are not bad. They can store up to 4k of data each for you, which you can read back when the user returns to the page. There’s a excellent little jQuery plugin I use to facilitate this called, aptly, jquery-cookie. You can download it (for free!) from GitHub here. Cookies persist across sessions.

Session Storage

Session storage is the flavor of Web storage that allows you to store data just for the duration of the session. Think of a session as a browser lifespan. Once you close the browser, the session storage is gone. Both session storage and local storage sizes are limited by the browser you are using. If you want to know if Web storage is available in your browser of choice, take a look at “Can I use“. The amount of storage each browser gives you is a moving target, but it’s per domain.

Local Storage

Local storage takes Web storage one step further. The data stored in local storage persists across browser sessions. In fact, it usually won’t go away until you explicitly delete it. (Consider this fact when you are gobbling up local storage in your development process.)

So What?

The trick with using these storage mechanisms is managing the data you’ve put in local storage as a cache. That data can go past its expiration date, either because some changes were made to the underlying data source or the cache itself has become corrupted. The latter is more difficult to deal with, so here I’ll focus on the former.

JavaScript – like most other programming languages – lends itself to building wrapper functions that add additional layers of abstraction on top of underlying functionality. Too many levels of abstraction can make things confusing, but with careful thought and smart code writing, you can build abstractions that serve you well.

In a recent client project, I found that as list data volumes were increasing, the pages in my SPServices- and KnockoutJS-driven application were loading more and more slowly. I’m building on top of SharePoint 2007 in this case, so even if I wanted to use REST, I couldn’t, nor do I believe that it would automatically make anything faster. If we had better servers running things, that might make a huge difference, but we have no control over that in the environment.

What I wanted was a reusable wrapper around SPGetListItemsJson (which itself is a wrapper around the SOAP List Web Service’s GetListItemChangesSinceToken and SPService’s SPXmlToJson) that would let me check local storage for a cached data source (list data), read either the entire data source or just the deltas from the SharePoint list, load the data into my application, and then update the cache appropriately.

The getDataSource function below is what I’ve come up with so far. There’s some setup to use it, so let me explain the parameters it takes:

  • ns – This is the namespace into which you want to load the data. In my applications these days, following the lead from the patterns Andrew and Scot Hillier (@scothillier) have published, I usually have a namespace defined that looks something like ProjectName.SubProjectName.DataSources. The “namespace” is simply a complex JavaScript object that contains most of my data and functions.
  • dataSourceName – The name that I want to give the specific data source within ns. In my example above with the Countries list I would use “Countries”.
  • params – This is the big magilla of the parameters. It contains all of the values that will make my call to SPGetListItemsJson work.
  • cacheItemName – This is the name of the item I want to store in Web storage. In the Countries example, I would use “ProjectName.SubProjectName.DataSources.Countries”.
  • storageType – Either “localStorage” or “sessionStorage”. If I expect the data to change regularly, I’d probably use sessionStorage (this gives me a clean data load for each session). If the data is highly static, I’d likely use localStorage.

And here’s the code:

/* Example:
getDataSource(ProjectName.SubProjectName.DataSources, "Countries", params: {
  webURL: "/",
  listName: "Countries",
  CAMLViewFields: "<ViewFields>" +
      "<FieldRef Name='ID'/>" +
      "<FieldRef Name='Title'/>" +
      "<FieldRef Name='Population'/>" +
      "<FieldRef Name='CapitalCity'/>" +
      "<FieldRef Name='Continent'/>" +
    "</ViewFields>",
  CAMLQuery: "<Query>" +
      "<OrderBy><FieldRef Name='ID'/></OrderBy>" +
    "</Query>",
  CAMLRowLimit: 0,
  changeToken: oldToken,
  mapping: {
      ows_ID:{"mappedName":"ID","objectType":"Counter"},
      ows_Title:{"mappedName":"Title","objectType":"Text"},
      ows_Population:{"mappedName":"Population","objectType":"Integer"},
      ows_CapitalCity:{"mappedName":"CapitalCity","objectType":"Text"},
      ows_Continent:{"mappedName":"Continent","objectType":"Lookup"},
    }
  }, "ProjectName.SubProjectName.DataSources.Countries"
)
*/

function getDataSource(ns, dataSourceName, params, cacheItemName, storageType) {

 var dataReady = $.Deferred();

 // Get the data from the cache if it's there
 ns[dataSourceName] = JSON.parse(window[storageType].getItem(cacheItemName)) || new DataSource();
 var oldToken = ns[dataSourceName].changeToken;
 params.changeToken = oldToken;

 // Read whatever we need from the dataSource
 var p = $().SPServices.SPGetListItemsJson(params);

 // Process the response
 p.done(function() {
 var updates = this.data;
 var deletedIds = this.deletedIds;
 var changeToken = this.changeToken;

 // Handle updates/new items
 if (oldToken !== "" && updates.length > 0) {
 for (var i = 0; i < updates.length; i++) {
 var thisIndex = ns[dataSourceName].data.binaryIndexOf(updates[i], "ID");
 // If the item is in the cache, replace it with the new data
 if (thisIndex > -1) {
 ns[dataSourceName].data[thisIndex] = updates[i];
 // Otherwise, add the new item to the cache
 } else {
 ns[dataSourceName].data.splice(-thisIndex, 0, updates[i]);
 }
 }
 } else if (oldToken === "") {
 ns[dataSourceName] = this;
 }
 // Handle deletes
 for (var i = 0; i < deletedIds.length; i++) {
 var thisIndex = ns[dataSourceName].data.binaryIndexOf({
 ID: deletedIds[i]
 }, "ID");
 ns[dataSourceName].data.splice(thisIndex, 1);
 }
 // Save the updated data back to the cache
 if (oldToken === "" || updates.length > 0 || deletedIds.length > 0) {
 // Save the new changeToken
 ns[dataSourceName].changeToken = changeToken;
 window[storageType].setItem(cacheItemName, JSON.stringify(ns[dataSourceName]));
 }
 dataReady.resolve();
 });
 return dataReady.promise();
}

Some of the nice things about this function:

  • It’s generic. I can call it for any list-based data source in SharePoint. (I started out building it for one data source and then generalized it.)
  • I call call it during a page life cycle to refresh the application data anytime I want or on a schedule, perhaps with setInterval.
  • I can set a lot of parameters to cover a lot of different use cases.
  • Each time I call it, it updates the cache (if it needs to) so that the next time I call it I get a “fresh” copy of the data.
  • It only loads the data that it needs to, by using the GetListItemChangesSinceToken capabilities.

And some downsides:

  • Since I know what data I’m working with in my application and that it will fit into the Web storage easily, I’m not worrying about failed saves.
  • If the cache does become corrupt (not something I expect, but there’s always Murphy), I’m not handling it at all.

KnockoutJS – Creating a Comma-Delimited List of Values

KnockoutJS LogoI’ve been building a lot of great stuff with KnockoutJS lately. It seems that it can enable many – if not all – of the development requirements I have these days, whether I’m building a single-page application (SPA) or just adding a snippet of content to an existing page. I can even build KnockoutJS-enabled “Web Parts” by dropping  a Content Editor Web Part [CEWP] into a page. It doesn’t matter what version of SharePoint it is.

The KnockoutJS documentation is generally very good, but sometimes I find the examples lacking a bit. It’s always tempting to make examples show off too much, which often leads to showing off too little. (I have this same problem with my SPServices documentation and examples.)

A common use case is wanting to display a set of values in a comma-delimited list. Let’s take this example. Say I have an observable array of Ticker objects, like so:

self.Tickers = ko.observableArray([
  {lookupId: 1, lookupValue:"SPLS"},
  {lookupId: 2, lookupValue:"APPL"},
  {lookupId: 3, lookupValue:"GOOG"}
]);

Because I’m pulling data from SharePoint, I want to hang onto the lookupId value along with the text value, which is what I want to display. Because of this a simple Tickers.join(“, “) doesn’t cut it.

I’d like to display the list of tickers like this:

SPLS, APPL, GOOG

Pretty simple, right? But after a little Binglage, I couldn’t find a concise example, thus this post.

If you check the KnockoutJS documentation for foreach, you’ll see that there is a variable available called $index. The $index variable gives you the zero-based index of the current array item.

So if I use foreach on Tickers:

<div data-bind="template: { name: 'Ticker', foreach: Tickers }"></div>

I can use the $index to determine if I should emit a comma. We don’t want to see a comma after the last value, so it requires this small bit of finesse.

<script type="text/html" id="Ticker"><span data-bind="visible: $index() > 0">, </span><span data-bind="text: lookupValue"></span></script>

It’s a little bit bass-ackward, but if the $index value is greater than zero – which it is for all values except the first one, where the index is zero – then we *prepend* a comma to the value.

Yes, I’m using a separate template to emit the tickers. That’s mainly because in my case I’m doing a little bit more than what I’m showing here. However, by creating a separate template, I have a reusable piece of markup. that I can use in many places.

I hope someone out there finds this useful!

References