Page MenuHomePhorge

Roundcube Next Shell
Updated 3,089 Days AgoPublic

Version 5 of 10: You are viewing an older version of this document, as it appeared on Nov 3 2015, 11:50 PM.
WARNING: This is a wiki used as a scratch-book. The texts on this wiki are being worked on actively, and are considered to be drafts.

What is the Roundcube Shell?

The Roundcube Shell builds the basic environment for the Roundcube Next client. It's based on Ember.js and provides the following core functionality:

As an application:

  • Authentication UI
  • Top-level navigation between full-page apps
  • User settings page (for simple account tweaks, password changes, etc)

As an API:

  • Access to the data store via the JMAP library
  • UI Toolkit with reusable components
  • Routing system with hooks
  • Pub/sub system for inter-component communication

JMAP data store

TBD.

UI Toolkit

When working with Ember, most widgets are contained within Components. Components which are expected to be repeatedly used within the various applications that Roundcube Next shall come with, ought to be provided as a reusable set by Roundcube Shell. This would range from simple things like buttons and labels to more complex components like list-views and editor toolbars.

Having all components in one place lets us keep them organized and allows for an easy way to customize the look of the entire application consistently, making it very smooth for designers and developers to work together. Every time a new reusable component is created, it should be added to a living styleguide. For realizing this, we shall use broccoli-livingstyleguide, which is designed for ember-cli backed toolchains.

Routing system

TBD.

Pub/sub system

The shell also provides a global event emitter system where all components and apps can use to publish notifications and subscribe to messages from other components. Each component shall emit events

  • whenever it reaches a point where the application state is changed
  • where it makes sense to inform others about a certain action
  • where feedback and/or additional/modified data is desired

This can begin with an shell.init event at application startup where apps can register themselves in the shell, define routes and push items to the main navigation.

The pup/sub is inspired by the Node.js events.EventEmitter component and primarily provides three methods for public use: on(), once() and emit(). Bonus points if the registration of event listeners with on() supports wildcard event names such as mail.message.*.

NOTE: Shall the App instance itself provide the pub/sub methods or shall we define a specific (singleton) module that can be imported? Any suggestions for existing libraries to use for this?

Works with Promises

Event listener should be able to work asynchronously and therefore return a Promise. The pub/sub system collects Promises returned by the registered listeners and returns a list of Promises to the emitter. Thus, whoever emits an event through the pub/sub system is responsible to handle returned promises and execute them. Example:

Promise.all(pubsub.emit('foo.bar')).then(function(results) { /* continue */ }).catch(...);

Naming conventions

Since the proposed pub/sub system is one global message bus, it's important to use unique names for the events emitted to it. A few rules apply for composing event names:

  1. each component (or app) emitting an event, shall prefix the name with its own namespace (e.g. shell.*).
  2. the general classification of the emitting component and the entity name shall be reflected in the event name (e.g. model.message or view.contactlist).
  3. finally, choose sane names describing the action performed before the event is emitted.
  4. by default, events are emitted after a certain action was performed.
  5. if events are emitted before and after the according action, this shall be reflected in the event name with the before and after keywords.

Here are a few examples, illustrating the just listed conventions:

  • shell.init
  • shell.ui.load
  • mail.model.mailboxlist.load
  • mail.model.message.flags.set
  • mail.view.mailboxlist.render
  • shell.account.settings.beforesave
  • shell.account.settings.aftersave

Documentation

In order to publish a comprehensive list of events emitted throughout the application, each component shall describe the emitted events and the provided parameters in a jsdoc block according to the JSDuck spec:

/**
 * @event mail.model.message.flags.set
 * Emitted when message flags are updated
 * @param {Mail.Model.Message} message The message object receiving flag updates
 * @param {Object} flags Map of flag names and their new values
 */

User Stories

The following user stories shall help outlining the application structure and explain how the different components contribute to the overall functionality of the application.

Rob logs in to the webmail to check for new messages

  1. He opens the webmail location in his browser
  2. He enters his username and password at the login prompt
  3. The main navigation shows a badge near the mail icon indicating 5 new messages
  4. Rob clicks the mail icon in the main navigation to open the mail view

Involved components and events:

  1. The shell renders the login form
  2. Upon submit, the shell authenticates through the JMAP adapter and activates the / route
  3. The shell emits the shell.session.authenticate event and the mail app fetches the number of unread messages from the server.
  4. The shell.ui activates the /mail route. the mail app renders the mail view and fetches the mailboxlist and the inbox messages from the JMAP data store.

Mary opens an email message for reading

  1. In the message list she clicks the new and yet unread message from Jane
  2. The message content is displayed in the preview pane on the right
  3. Next to the email sender name a green icon indicates that Jane is now online on Jabber
  4. After a few seconds, the clicked row in the message list looses the "unread" indicator

Involved components and events:

  1. The mail app activates the /mail/message/md2f58fbc8 route
  2. The mail app fetches the message from the JMAP store and emits the mail.model.message.load event. The jabber app compares the message headers (from, to, cc) with the presence information from the roster.
  3. The mail app renders the mail view and emit the mail.view.message.render event. The jabber app extends the message header view with presence indicators for sender and recipients.
  4. Once the message is shown for 5 seconds, the unread flag is removed from the message model which updates the list view. The changes are synchronized to the server through the JMAP data store.

To be continued ...

Last Author
bruederli
Last Edited
Nov 3 2015, 11:50 PM