Coming Soon: Tempo Teams

2009-10-27 20:00:00 -0400


Team Tempo Assignments

Over the last year a whole lot has changed with Tempo, our time-tracking system. Actually, in the last two years the system has seen constant development and two major re-designs as we added features, responded to our customers’ feedback, and addressed rather-justified gripes about our lack of design skill shown in the early revisions. At this point Tempo has a fantastic look and feel, is extremely stable, and has a satisfied and steadily-growing base of free users and paid subscribers.

However, all that work takes a long time and involves a great deal of testing, usually with a number of our customers helping us beta the changes before release, for which we are quite grateful. After a major revision of Tempo is released, there’s always a period of adjustment for our users, too, so there’s a hidden cost there as well.

With that in mind, I’m happy to say that the next major revision of Tempo, Teams, is almost here, and should involve very little adjustment for those who are using the system every day. The changes are big, but they are mostly below the surface. This revision makes Tempo a lot more flexible for us and our customers, and is allowing us to implement some oft-requested features from our long-time users. This revision is called Teams because it is specifically aimed at making the management of a team on Tempo as easy as it ought to have been in the first place.

If you’d like to get an early look at the new system, please get in touch with us and we’ll send you the link and some short instructions.

Here’s a list of the bigger changes:

  • Quick assignment of users to multiple projects.
  • All paid users will have an account associated with their user identity.
    • Free users working on their own will also have accounts generated.
  • All of these accounts have their own subdomain (e.g. zetetic.keeptempo.com).
  • Accounts can have managers with more control than project managers.
  • All people on your projects have been copied or moved into your account.
  • Paid plans will be scaled by people-per-account, not people-per-project.
  • Every paid account is gifted an extra two users to accommodate that change.
    • e.g. Moderato accounts with 10 users on various projects would be get 12 users.
  • Auto-detection of mobile browsers for an updated mobile view.
  • Legacy support for the ‘m.keeptempo.com’ mobile address.
  • Saved Reports can be organized into groups.

We haven’t set a release date just yet, but we’re aiming for the middle of November, so that we can address any issues before the end-of-month billing period.


Working with mobile-fu and Rails

2009-10-22 20:00:00 -0400


Tempo Mobile Login

Bret and I have been working on a pretty extensive update to Tempo, our time-tracking service, that required revisiting how we detect mobile devices and provide mobile views where appropriate and/or available.

To that end I took a look at mobile-fu, a Rails plugin by Intridea’s Brendan Lim, which automatically detects mobile devices and sets the request format to :mobile, a commonly used mime-type alias for those looking to provide mobile views. You can check out his blog post on the plugin for full details, but the basics of it are that by setting the request.format to :mobile, you can automatically serve up custom views (e.g. new.mobile.erb), perhaps in a custom layout, etc. The plugin also will automatically attempt to include mobile_blackberry.css if you are already including a mobile.css file and the user is working off of a blackberry.

That’s almost perfect! However, we don’t support mobile views all over Tempo, it’s a bit impractical at the moment, especially given how well smart phone browsers like Mobile Safari handle normal web pages. Instead, we provide a basic mobile interface for logging in and logging time. We do want that to render automatically, but we also want the user to be able to exit out of the mobile view easily, and have that stick with his session.

So I forked mobile-fu on github, got things working the way I needed ‘em, and posted the changes back up. It now provides automatic detection of mobile devices with more dynamism (you call before_filter yourself, where you want it, with the options you need), and you can use the ’bypass’ parameter on any request to toggle the session-based bypass of the mobile view that allows the user to avoid it if he doesn’t actually want it.

Pushed-to-github-and-blogged-too-soon Update:

The use of a ‘bypass’ in the way I’ve done it here becomes somewhat less useful when you want a user to be able to easily enable the mobile view when their mobile device is not detected (e.g. a ‘Switch to Mobile View’ link on the login screen). So, I’ve hacked away at this a bit more and I’ve got another implementation to commit and push to this fork when I get a few minutes.

The main problems I ran into in all of this were not really the problem of mobile-fu, but more of an issue with how Rails handles the use of request.format, the aliased mime-type (i.e. :mobile => 'text/html'), and forwarding from one domain to another. Will try to detail how we’re handling it all shortly.


Get Excited and Make Things

2009-10-19 20:00:00 -0400

Designed by Mr. Matt Jones, of the British Experimental Rocket Group (BERG):

Make Things

You know you want one. I just ordered mine.

BERG does amazing things like this:

Immaterials: the ghost in the field from timo on Vimeo.

Been real busy here at Zetetic HQ. Bloggery to resume soon!

Strip Updates On the Way

2009-09-09 20:00:00 -0400


I was intrigued by Steven Frank’s recent blog post describing how Panic software approaches communicating with customers about feature announcements and product updates. Like Panic, we tend to say little, work a lot behind the scenes, but it sounds like once in a while it’s a good idea to get out in front with a blog post to let your customers know what we’ve been working on and what’s coming.

Our primary development focus with Strip at the current time is a replication library that will be the core of our sync process, and it will likely become an open source project. Many folks have been emailing us to say that they love Strip on the iPhone, but they need desktop sync, and some of them miss the old beaming functionality of STRIP on their Palm devices. The replication engine is almost complete, and is the key to enabling these additional pieces of the Strip platform.

Meanwhile, we’ve got a maintenance update brewing for Strip on the iPhone. We expect the following issues to make it in to the next update, time permitting:

  • Bug: Loss of typed data on lock out while creating a note. (Fixed)
  • Convert existing database cipher mode to improve compatibility with standard SQLCipher configuratione. (In-progress)
  • Rename Lite → Strip migration button for clarity. (Fixed)
  • Fun: Facebook Connect hook for spreading the word. (Complete)
  • Allow copy & duplication of entries so that you can create “template” entries or share common fields. (In-progress)
  • Protect database re-key from application interruptions. (In-progress)
  • Enable FTS3 (full-text) searching, search on type.
  • Bug: Attempts to re-order the Add Field row cause a crash.
UPDATE: have just released a free Palm Strip Export utility for Windows that can dump your Palm OS 2.0 databases to a CSV text file. Check it out here.

acts_as_union to the Rescue

2009-09-06 20:00:00 -0400


So here I am, minding my own business on Labor Day, working on the upcoming teams branch of Tempo. Basically, it introduces a new account model that’s distinct from users and projects, ideally facilitating the setup of teams for small organizations. Accordingly, an account has an owner, and every user belongs to an account. In addition, users can be managers for the whole account (new!), or users can be marked as a manager for a particular project assignment.

This all sounds great on paper, but in the Projects controller there arise a number of concerns:

  • The account owner or one of the managers should see all the account’s projects on the projects index, and also the /archive resource collection
  • All other users should only see accounts they are assigned to as managers
  • index should only show active projects and archive should only show inactive projects
  • index and archive both support an id parameter for the XML api, enabling the lookup of an aribitrary collection of managed projects

As you can imagine, this could lead to a lot of spaghetti in a controller method, that you’d want to hide away in a model. Typically, you’d want your User model to set up the various project collections as association (has_many) resources so you can provide find options as needed (such as :conditions => { :is_active => true }). That keeps your redundancy down, but your controller (or a model method) would have to conditionally decide which resource to provide. There was the possibility of adding a method to the user model that handled the conditional logic and passed back the right result set, but it would have been a royal pain to correctly pass through find options, especially given all the various circumstances above..

To make things further complicated, we need to also use these methods for the reporting interface and to make sure users only see the time entries they are supposed to see. That means keeping nonsense and code repetition to a minimum is critical.

That’s where acts_as_union saves the day!


has_many :managed_projects,
:source => :project,
:through => :assignments,
:conditions => [ 'assignments.is_manager = ?', true],
:order => 'projects.name ASC'
has_many :owned_projects,
:source => :projects,
:through => :owned_account,
:order => 'projects.name ASC'
acts_as_union :manageable_projects, [ :owned_projects, :managed_projects ]

ActsAsUnion is included in our ActsAsNetwork plugin, and it allows us to UNION together multiple associations and operate across them as we would any other association, by supporting the various find_* options we are used to with has_many.

Now I can do any of the following:


@projects = @current_user.manageable_projects
@projects = @current_user.manageable_projects.find(:all, :conditions => { :is_active => false})
@projects = @current_user.manageable_projects.safe_find_from_ids(params[:id])

On a tangential note, safe_find_from_ids is a quick and dirty monkey-patch we throw in an initializer so we can look up a set of ids that returns an empty set instead of raising an exception when no ids are found:


class ActiveRecord::Base
def self.safe_find_from_ids(*args)
ids = args.kind_of?(Array) ? args.flatten : [args]
ids.empty? ? [] : self.find(:all, :conditions => ["#{self.table_name}.id IN (#{ids.collect{|p| '?'}.join(',')})", ids].flatten)
end
end

It’s not ideal, but it gets the job done. There may be a better way of doing it in recent versions of Rails, need to look into that.

Happy Labor Day!

Zetetic is the creator of the super-flexible Tempo Time Tracking system.