How to manage multiple Trello Boards with MultiBoardForTrello, my first Open Source React App

How many of you use Trello to plan upcoming sprints or weeks of your product roadmap? And how many of you use various boards to properly plan projects of multiple clients (or projects)? And how many of you keep switching between several open tabs to plan and keep them in sync?

If you are like me (and probably many of you are), you will answer these questions with “I do”. Today I am going to present you a potential way out of this situation.

After finish reading “Show Your Work!: 10 Ways to Share Your Creativity and Get Discovered” by Austin Kleon (Kindle, Paperback), I finally take the time to write an extensive post about my very first react Open Source project:

“Multiboard for Trello”. #showyourwork

If you want to see the app in advance, try the example. Don’t worry, all the data from Trello will not be accessible outside of the browser tab! The app does not send data recieved from Trello’s API to a 3rd party.

Some of you might not have the time to read more about the progress from the start to the end. You probably just want to install, start and test the multiboard. Let’s see how this works. First of all, you have to clone the repository:

Once you have installed the dependencies with npm install, follow the “Setup & Configuration Quickstart” guide. When you have configured everything, start the app on your local machine with npm start and open http://localhost:2222/.

You should see the dashboard with the configured boards, lists, members, and cards now. You can even install and set up Google Analytics, if you want.

When everything looks as expected, build the app with npm build and publish the files in dist on your server. Voilà, you have just released the App. Congratulations!

If you want to know more about the idea, progress and final product keep on reading now.

At the beginning of 2018 my colleagues from Lovely Systems and I attended the AgentConf in Dornbirn. It was the first developer conference I went to, since I started my new career as a developer last year. This made me absorb as many information, best practices and advice from the speakers and developers as I could.

Until today, one thing stuck in my head. Many speakers (especially Max Stoiber, creator of styled-components) encouraged us to share more of our work with others, to open source more and constantly give value back to others. This idea matured in my head. In the past, I published some smaller ideas on Github already (eg. speedtest-cron and an Alexa skill from the last uma hüsla hackathon). But this time, I wanted to share a React App in a more professional and dedicated way.

And that is how it came, that on the 13th of March 2018 I committed the first few lines of code on Bitbucket for what’s going to become my first React open source project on GitHub.

Image for post
Image for post
Oftentimes I have multiple tabs open (eg. side-by-side) to manage and sync boards.

In the past years, I worked together with several startups and teams (eg. Rawr, Squabble, reachbird and Wegfinder). During that time I had to keep track of more than one Trello board as a result. Each team had its own boards (sometimes multiple ones for advertising, development, and others), its own members and commitment per sprint (Note: We used to work in Scrum or Kanban mode). Maybe you know this situation already, especially if you work for an agency this is most likely the default setup in Trello.

Sooner or later, I had troubles to remember which team was working on which task, what I was supposed to do in which project and what’s planned for the following few weeks. “Trello Board Tab Hopping” became a daily routine for me. There was no easy way of seeing all the cards on one screen.

When I started to work for Michael Breidenbrücker at AlpineStartups (now known as speedinvest.studio) in 2015, I planned lots of the stories with Manfred Schwendinger (CEO of Lovely Systems). We began to have weekly sessions on Fridays with breakfast and lots of ideas what’s next for Rawr.

In one of our meetings, Manfred complained about the problem of managing multiple boards. He showed me a rough prototype and idea rendering multiple cards of several Trello boards on a dashboard. There was a “Tasks”, “Working” and “Done” column containing all the cards of the current sprint of all members across some boards. I was hooked and ambitious to see my previously gained knowledge from codeacademy courses and my passion for software development in action. The very first concept of a Multiboard for Trello was available on GitHub some weeks later.

A few sprints after releasing the first version, the tool was used in two teams already. But sooner or later we fall back into the old routine and forgot about the app. Until now.

Image for post
Image for post
This example illustrates the App with three boards, 2 members, and 5 sprints. You can switch between the sprints and filter members, for instance.

Approximately two years later, after attending the Agent Conf, I thought about open sourcing a React app (or something similar) once more. That is when I got in touch again with the multiboard idea repeatedly, whilst planning the next sprint with our team at Lovely Systems on our planning day.

Before I started, I tried to focus on answering the “WHY”. Why should one use a tool like this? What’s the benefit? For me the answer is simple. You get a focused overview of all currently (filtered lists) important tasks (cards) of all your projects and clients (boards) on one screen.

Sounds good, right? Then let’s do it!

Before coding, it was time to think about the features and HOW I would going to build the app. The following should be part of the Minimum Viable Product (MVP):

  • A proper UI/UX with Material UI
  • All cards of filtered lists of multiple boards (eg. all lists containing “Working” in their name of several boards) rendered on one screen
  • Member filters (be able to filter all cards by a given member)
  • Display estimations (planned and consumed), based on the pattern of ScrumForTrello

Other planned features (some were added by now):

  • deep linking (eg. selected member with only his cards)
  • multiple sprints (weeks): filter more list patterns and render a “tab” for each of them
  • add private and public boards: the user does not have to be a member of the boards
  • and more…

Once the features were defined, it was time to start planning the SPA (SinglePageApplication). Compared to the old app, I had a broader repertoire of technologies in my mind this time. Additionally, I wanted to apply and demonstrate my previously collected experience as a developer. As a helpful side effect, so to speak, it would create and showcase my portfolio on GitHub.

The first thing to do was to plan the technology stack of the app. I wanted to use at least these technologies, libraries, and SasS tools:

Now, enough talked about the “HOW” from a bird view perspective, let’s focus on the “WHAT” I did to build the app. Note, as I write this most of the progress is already pushed to GitHub and I can remember only some of the pitfalls, learnings and “Aha!” moments during the journey. However, I will do my best to recall as many of them to let you join the journey with me again.

Development Setup

Create-React App or not? That was one of the first questions that popped up in my head. In favor of learning how to set it up from scratch, I decided to not use this or another boilerplate.

Installing the proper webpack and babel setup, was one of the first tasks. After stumbling upon some webpack 4 issues (eg. how to use extract-webpack-plugin again), it resulted in the following webpack setup. You will find a base config (valid for all environments), one for development and two (one for analyzing the bundle and the other for the final build) for production.

This is the base config for instance:

Let’s take a brief look at some of the configured webpack features:

Webpack can now be used with the npm script: npm build (production) and npm run build:dev (development).

But webpack is not enough, I need to set up babel as well to use the latest and fancy javascript features. What is babel you might ask? Let’s take a minute and see how babel describes itself:

Babel is a JavaScript compiler
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backward compatible version of JavaScript in old browsers or environments.

It allows us to use new features, like template strings, spread operators, and arrow functions. You can see a comprehensive list here: https://github.com/lukehoban/es6features.

So I installed all required babel dependencies, most importantly babel-preset-env, babel-preset-react, and babel-preset-stage-2. And finally, a proper .babelrc file has to be added to the root folder. Check out mine for the Multiboard App here:

You’ll see that I instruct babel to compile my Javascript code for Chrome 54+, and Safari 10+. At this point, I do not care about Internet Explorer ;)

You’ll notice "modules": false. According to the docs, it should enable the tree-shaking feature of Webpack. You can verify and see it in action with webpack-jarvis (webpack bundle analyzer). Keep in mind to use import instead of require to make it work (Note: I did not extensively test and make tree-shaking properly work in this project though.).

The env object allows us to activate certain plugins in different environments. For instance, I activate and use transform-react-remove-prop-types only in production. This can help to decrease the size of the bundle for production, as in this case we remove PropTypes and save bandwidth.

Just recently, I stumbled upon the article “Put Your Webpack Bundle On A Diet” by Benedikt Rötsch and found some improvements. Especially the “Only transpile what you need to with babel-preset-env” part will be added to my to-do list of improvements. And as Babel v7.0.0-rc.1 is released already, I will take a look at useBuiltIns: ‘usage' as well. Sounds promising. Here’s how you can upgrade and migrate to v7.0.0.

Image for post
Image for post
Credits: https://nttr.st/2B3Whxb

Okay, now I am able to build the app (npm build) and receive everything I need for a release in the dist folder (including the HTML, js and css files). You can simply upload the files to Netlify or another static file hoster and voilà the app is online.

But the app does nothing right now. We just handled the transpiling and compiling of the files. So let’s take a look at the routing, the components, and the redux store implementation.

Routes & Pages

I decided to use connected-react-router as my router component. It’s implementation works similar to react-router-redux (which was deprecated).

In my app each route renders the requested path’s <Page /> component as a child of <Layout /> (which adds an ErrorBoundary and CookieNotice to each page). For instance, the privacy page renders the markdown content of privacy.md. And the app page renders the <MainApp />. This pattern allows me to configure each page individually, by still applying the same <Layout /> to each of them.

The configuration for the route of each page is declared in pages-config.js and the routes composed in routes/index.js. This allows me to use the pages-config.js in other places. By passing the current details about the page from the <Layout /> to the <AppMenuContainer />, I am able to not only use it for routing, but also for the Sidebar menu.

So far so good, but how does the UI look like and get it’s data from?

Components (HoCs and Styling)

Presentational and Container Components

Before we take a look at the redux implementation and data handling, we will talk about components. When you work with redux, you sooner or later stumble upon the “Presentational and Container Components” article by Dan Abramov.

The main message of the presentational and container components approach is the following. presentational components care about how things look, are not aware of the store, read and change data by using and invoking props (provided by the container). The container component, on the other hand, cares about how things work (data fetching, state updates), subscribes to the store and dispatches actions and are usually created with connect, compose, recompose or in another way (eg. lodash.flow).

The Multiboard app applies this concept as well. For instance, let’s take a look at <EstimationCard />. You will find the following files: index.js and component.js in it’s folder. The index.js exports the HoC (HighOrderComponent) called <EstimationCardContainer /> and is connected to the redux store, prepares the data and enhances the <EstimationCard />. Other components are similarly structured.

UI and UX

For the UI and UX experience, I decided to use MaterialUI. Not only do they allow one to develop faster (as they offer lots of components), they are easily customizable as well. By customization I mean one can easily adjust colors, borders and other styling attributes. Le’s take a look at an excerpt of the <Member /> component. It illustrates how to style one of their components.

As you can see you first need to import withStyles and decorate your component with it. Then you can define custom styles. In our case, we overwrite roots padding. To get to know how and what can be overwritten, you have to take a look at the API of the MaterialUI component, in this case, CardContent. It only has one CSS API: root. Other components might have more, like the Grid component.

Besides styling the components with the CSS API, I used styled-components. Sometimes it was faster than creating yet another .scss file, import it, etc. (example). But above all, I wanted to test them for the first time. They are really awesome. :)

Another way of styling components of react-trello-multiboard is styling the UI with .scss. Since my friend Florian Hämmerle (CEO of BetterThingsDigital) introduced me to BEM, I cannot remember how I styled websites ever before.

Even if you do not use utils like react-bem-helper or bem-classnames, one should give their approach a try. Check out <TrelloCard />‘s styles.scss and card.js to see an example implementation.

Excursion - BEM

In a nutshell, this is how BEM works: BEM stands for “Block-Element-Modifier”. A Block is a standalone entity that is meaningful on its own. An Element is a part of a block, without a standalone meaning, for instance, a headline. And finally, use Modifier to flag an element to change its behavior, state or appearance. Take a look at this illustration for more details or the example from react-bem-helper below:

BEM Example

Redux Store (Actions, Reducers, and Middleware) & Trello API

Okay, so far we have put the routing in place, developed and styled some components. Now we have to take a look at how we fetch data from Trello and save them in the redux store. When I started this project, rebuilding the old app, I developed years ago, was one of the first approaches to get to know the Trello API again.

Trello API

First of all, you have to include Trello’s client.js with a proper APIKey(get one for your app) in your index.html file. From then on Trello is available in the app. Invoking Trello.authorize to authenticate the user is the next step. Trello will store an authorized token in the browser’s localStorage. Our app can now use trello.get to query data from Trello’s REST API.

This is basically how the multiboard app handles it (check out data/trello.js). First, the user is authenticated, then the required data fetched, redux actions dispatched, to save the result in the store, and voilà the containers have the necessary data available for the presentational component. You can take a look at the app’s reducers and reconstruct the store’s schema.

Receive the boards and lists

I will briefly show you now which endpoints I used to create the app. This is the flow of requests, to access all the data I need. First of all, I need to access the configured boards and their containing listIds:

  1. Query all boards of the authorized user by dispatching the requestBoards action. The response contains a list of the user’s boards their id and name. The first query is /member/me/boards?fields=id,name.
  2. Now all boards are fetched. But only the ones that match the filter configured in config.js of the app will remain. Additional data is requested for them. An array of ids of all boards’s lists is received with /boards/${boardId}?fields=id,name.
  3. The final result (the configured boards and the array of listIds) is saved via the board’s reducer in the store.

As this is in redux’s nature, changes in the redux store will cause subscribed containers to update. In this step,<BoardsList /> will render a<Board /> for each received board. Now let’s take a closer look at <Board />. Once it is mounted, it requests more data for each listId, by dispatching requestLists. Let’s take a look at this action:

  1. Query /boards/${boardId}/lists?fields=id,idBoard,name to get an array of all lists of each board and once more store the result in the store.
  2. The active list filter (to show only one selected list in the UI) is extracted from either history.location.search, history.location.hash or from config.js. Note: All boards use the same pattern to filter their lists.

At this point, you might notice there is room to improve data handling and performance (eg. to merge both requestBoards and requestLists). This could be achieved by changing the query to/member/me/boards?fields=id,name&lists=open&list_fields=id,name and only query it once (already on my todo list).

But as KentBeck said “Make It Work. Make It Right. Make It Fast.” And as of now, it works. :)

Receive the cards

Now let’s receive the cards. At this point we have rendered a <TrelloCardsList /> for each received list in the <Board /> component already. What’s missing is to render all the<TrelloCard />s of each list. The list of cards, and the data is fetched (like in the previous components) when the <TrelloCardsList /> is mounted. Once thereceiveCards action got all the data, all cards are presented in the dashboard. I use the following query for that: /lists/${listId}/cards?members=true&member_fields=avatarHash,fullName,initials,username&fields=badges,labels,name,id,idBoards,idList,idMembers,shortUrl

Receive and sum up estimations

What’s left is adding the estimations, of each card, to the preferred (filtered) members. The configured members (see config.js) were already fetched by the <MainApp /> in the componentDidUpdate hook (with this action and this query).

<TrelloCard /> will invoke the addEstimations actions, which will be handled in both the boards and members reducers eventually. They find the right board or member in the store and sum up the received estimations. This happens for all cards individually. It will end up in an overview of estimations (consumed and planned, based on ScrumForTrello) for each member and board in the UI.

Voilá, that’s the entire data fetching magic. From now one, the store can be either manipulated (eg. reset or recalculate estimations) or used to update data.

Image for post
Image for post
Credits: https://nttr.st/2KMKdzP

“Wow, that’s a lot of details and information”, you might think at this point. How will one be able to remember the required details to develop or set up the app?

Exactly, what I thought whilst developing. How can I help other developers start developing or using “Multiboard for Trello”?

Changelog

First of all, a valuable and informative changelog was required. Reading KeepAChangelog.com inspired me a lot. Their approach of writing and maintaining a log of changes helped me not only in this project but also at work it improved my documentation skills.

Let’s take a look at their guiding principles:

- Changelogs are for humans, not machines.
- There should be an entry for every single version.
- The same types of changes should be grouped.
- Versions and sections should be linkable.
- The latest version comes first.
- The release date of each version is displayed.
- Mention whether you follow Semantic Versioning.

Their principles make total sense to me. As well as their proposed types of changes:

- Added for new features.
-Changed for changes in existing functionality.
-Deprecated for soon-to-be-removed features.
-Removed for now removed features.
-Fixed for any bug fixes.
-Security in case of vulnerabilities.

If more people in a team bear this guideline in mind, reading the changelog will become more informative, efficient and valuable.

Spread the word and help me improve changelogs. :)

Documentation

Besides an informative changelog, a proper documentation is mandatory. I thought about creating an extensive documentation, eg. something with Jekyll or readthedocs. As of now the README.md offers enough possibilities to introduce the app to others in my opinion.

In the app’s README you can read lots of details about:

Additionally, in some parts of the js-code, I added links to more details and examples. You may stumble upon them when contributing or taking a look at the code.

A list of pitfalls and Aha! moments was promised to be part of this article in the introduction. So let’s take a look at the two of them I still remember.

One of the main features was filtering members. This meant to hide cards (with css or do not render them) from other members. At first, it seemed to work straight out of the box. Hidding iframes, created by the Embedding feature provided by Trello, worked. But whilst testing and clicking on member cards, I experienced a strange behavior. When re-rendering the cards it took too much time to render them again. Some even did not appear again. But it was not my app I figured out. It was part of Trello’s embed.js’s behavior. They fetch new data in an interval. As soon as the iframe is not visible anymore they set the height of the iframe to 0px. When it is visible again it takes time for the embed.js to take notice of this change (next polling cycle) and update the iframe once more. This was not working as expected. At one point I decided to create a custom TrelloCard React component (Codepen) and handle it myself.

Another Aha! moment was when I researched how to scroll horizontally. How should I structure the component hierarchy to enable x-axis scrolling with overflow? I did not want to enable this on the entire page. And was there something I need to consider on mobile? Whilst researching, I stumbled upon some interesting codepens and articles. They all showcase how to build a Trello board with horizontal scrolling. Finally, I knew how to implement it. Here are some of the articles:

What’s still left is a feature like drag&scroll, similar to Trello’s implementation. Currently, it is easier to scroll horizontally with the touchpad or on mobile than on a Desktop with the mouse wheel. It’s on the todo list. :)

Image for post
Image for post
Credits: https://nttr.st/2Mi3Btv

If you are interested in React, have new ideas, or just want to contribute to make the app better, let me know, please! We can discuss it on Twitter.

If you find an issue report a bug, please. If you have a feature request open an issue, as well when you have a question.

Again, feel free to contact me on Twitter.

So far you have seen a lot what the app is capable of now. “What’s released next?”, you might ask. I have thought about this a lot recently and whilst writing. The following ideas are on the roadmap and in my mind:

  • Docker Image (for easier and quicker setup, if you do not want to care about npm or other development and build tools), even though this might be too much for a static page.
  • subscribe to updates (polling), similar to Trello’s embed.js
  • edit cards (eg. the title, members, and labels, but no drag and drop support for now)
  • i18n support (with react-intl)
  • Working view: display tasks (eg. from checklists) in a “todo”, “working”, “review” and “done” table. This would allow one to not only display the “bird’s-eye view”, but also details of the current sprint. Something similar to scrumy’s UI.
  • Drag & scroll support

If you are interested and want to help or have other ideas, let me know, please.

I have written quite a lot about one of my first open source projects by now. There is not much more to conclude left. Besides my commitment to further work on more open source projects in the future. There are already two new ideas (already in progress) on my table. But this time, I will post more articles during development to keep you in the loop. So stay tuned, by either following me on Twitter or on Medium.

Written by

I am a Software Engineer from Austria 🇦🇹. I write about JavaScript, TypeScript, ReactJS and NodeJS. 📧 Weekly NL Series: https://newsletter.natterstefan.me

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store