Feb 16 2012

Quick Poll–UX of UI navigation for list with a single item

Category: Software DesignRory Primrose @ 17:31

I’m after some feedback from the community regarding the UX of UI navigation when dealing with a list of items where there is only one item in the list.

I have a scenario in a UI where there is a list of subscriptions for a user account. Most of the time (~>90%) there will only be one subscription. There are two options for handling this.

  1. Always display the list when the user navigates to the list UI and force the user to manually select the only item available
  2. Automatically redirect the user to the item display screen if there is only one item

Option #1 is consistent but includes an unnecessary navigation (+ human intervention). Option #2 is streamlined, but provides an inconsistent UX when the list changes to have a second item.

I have leant towards #2 because of the expected metrics of my specific scenario in addition to it being more streamlined. The point of inconsistency is a thorn in my side however.

Thoughts? Votes? Any UX experts want to shed some opinions?

Tags:

Feb 7 2012

Finding solutions not covered by automated builds

Category: Rory Primrose @ 12:01

I am slowing building a set of automated tasks in my current role as a TFS administrator to verify the state of TFS. My latest task looks for solutions that are not covered by automated builds.

It’s a fairly straight forward task that enumerates solution files and matches them to build definitions across all projects and collections in a TFS instance.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Xml;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.VersionControl.Client;

namespace TFSVerifier
{
    [Export(typeof(ITask))]
    public class FindSolutionsWithoutBuildsTask : ITask
    {
        private Uri TfsAddress = new Uri("http://[TfsAddressHere]:8080/tfs", UriKind.Absolute);

        public string Name
        {
            get { return GetType().Name; }
        }

        public void Execute()
        {
            TfsTeamProjectCollection server = new TfsTeamProjectCollection(TfsAddress);

            server.EnsureAuthenticated();

            TfsConfigurationServer configurationServer = server.ConfigurationServer;

            ReadOnlyCollection<CatalogNode> collectionNodes = configurationServer.CatalogNode.QueryChildren(
                new[] { CatalogResourceTypes.ProjectCollection },
                false, CatalogQueryOptions.None);

            collectionNodes.ToList().ForEach(x => ProcessCollection(server, x));
        }

        private void ProcessCollection(TfsTeamProjectCollection server, CatalogNode collectionNode)
        {
            Guid collectionId = new Guid(collectionNode.Resource.Properties["InstanceId"]);
            TfsTeamProjectCollection teamProjectCollection = server.ConfigurationServer.GetTeamProjectCollection(collectionId);

            ReadOnlyCollection<CatalogNode> projectNodes = collectionNode.QueryChildren(
                new[] { CatalogResourceTypes.TeamProject },
                false, CatalogQueryOptions.None);

            projectNodes.ToList().ForEach(x => ProcessProject(server, collectionNode, x));
        }

        private void ProcessProject(TfsTeamProjectCollection server, CatalogNode collectionNode, CatalogNode projectNode)
        {
            String projectName = projectNode.Resource.DisplayName;
            
            VersionControlServer versionControl = server.GetService<VersionControlServer>();
            ItemSpec spec = new ItemSpec("$/" + projectName + "/*.sln", RecursionType.Full);
            ItemSet set = versionControl.GetItems(spec, VersionSpec.Latest, DeletedState.NonDeleted, ItemType.File, false);

            if (set.Items.Any() == false)
            {
                return;
            }

            IEnumerable<String> solutionsInProject = from x in set.Items
                                                     select x.ServerItem;

            IBuildServer buildServer = server.GetService<IBuildServer>();
            IBuildDefinition[] definitions = buildServer.QueryBuildDefinitions(projectNode.Resource.DisplayName, QueryOptions.Definitions);
            IEnumerable<String> projectsBeingBuild = ProjectsBuiltInProject(definitions);
            IEnumerable<String> projectsNotBeingBuild = solutionsInProject.Except(projectsBeingBuild);

            if (projectsNotBeingBuild.Any())
            {
                Console.WriteLine(collectionNode.Resource.DisplayName + ": " + projectName);

                Console.ForegroundColor = ConsoleColor.Yellow;

                projectsNotBeingBuild.ToList().ForEach(x => Console.WriteLine(x));

                Console.ForegroundColor = ConsoleColor.Gray;
            }
        }

        private IEnumerable<String> ProjectsBuiltInProject(IBuildDefinition[] definitions)
        {
            foreach (IBuildDefinition definition in definitions)
            {
                IEnumerable<String> projectsToBuild = ProjectsToBuild(definition);

                foreach (String projectToBuild in projectsToBuild)
                {
                    yield return projectToBuild;
                }
            }
        }

        private IEnumerable<String> ProjectsToBuild(IBuildDefinition definition)
        {
            XmlDocument doc = new XmlDocument();
            XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable);

           manager.AddNamespace("y", "clr-namespace:System.Collections.Generic;assembly=mscorlib");
            manager.AddNamespace("x", "clr-namespace:Microsoft.TeamFoundation.Build.Workflow.Activities;assembly=Microsoft.TeamFoundation.Build.Workflow");

            doc.LoadXml(definition.ProcessParameters);

            XmlNode node = doc.SelectSingleNode("//y:Dictionary/x:BuildSettings/@ProjectsToBuild", manager);

            if (node == null)
            {
                return new List<String>();
            }

            String projectsToBuild = node.Value;
            String[] projects = projectsToBuild.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            return projects;
        }
    }
}

Enjoy

Tags: