Task management can be gruelling. For managers, monitoring tasks that are scattered and disconnected from one another remains just as much a norm as a bane in their profession. Being able to instantly understand the progress of projects without having to waste time digging for this information is an invaluable asset to any manager.
Having a project management system that can provide a clear visualization of the progress of each assignment will save time, reduce errors and allow managers to plan their next move with more precision.
Such an application requires a powerful database to effectively display graphs and resources to the user, which is why this Launchpad App used Redis to create its own project management application.
RedisGraph was at the start of this application, due to its ability to simplify the traversal of highly connected data and deliver contextual insights.
Let’s take a look at how they managed to bring this project to life. But before we dive in, make sure to check out our range of exciting apps on the Launchpad.
You’ll build a powerful visual project management application that will help users visualize and categorize tasks whilst highlighting the different relationships between them using Redis. A task can be an idea, goal, epic feature, simple task or bug.
From start to finish, the core objective of this application is to make monitoring clusters of tasks simple and easy. Below we’ll take you through each step,along with the required components and their functionality.
Install the below software:
First, ensure that you have a working Docker environment. Pull the images and start the containers:
docker-compose up -d
code-red % docker-compose up -d
[+] Running 5/5
⠿ Network code-red_default Created 0.1s
⠿ Container code-red_postgres_1 Started 1.6s
⠿ Container code-red_redis_1 Started 1.6s
⠿ Container code-red_reset_1 Started 3.3s
⠿ Container code-red_app_1 Started
docker-compose run --rm app bin/webpack
docker-compose exec app rails db:setup
Database ‘codered_development’ and ‘codered_test’ gets created.
Once you’ve set this up, load the sample data into the PostgreSQL and Redis databases:
docker-compose exec app rails database:seed
docker-compose exec app rails database:seed
== Creating users ==
== Creating projects ==
== Creating tasks ==
The application should now be available at http://localhost:3000.
First click on the plus sign on the top left hand side of the screen to create a new task. You’ll then be presented with the below image. At the top you can create a title for the task along with a description in the text box below.
Sitting just below the title you’ll see a panel of drop down menus. On the far left you can decide on the nature of the task. In the middle you can set the due date for the task to be completed and on the far right you can assign the task to a specific individual.
A core benefit of this app is being able to see the relationships between different tasks, as you’ll see from the following image.
To achieve this, first click on a task to get access to its core menu. From here you’ll see a drop-down menu at the bottom called ‘Add relationship’ (see image below), where you can decide what relationship this task will have with others.
On the right-hand side of this bar, you can choose which task you want the relationship to be shared with.
As a user, you’ll want to view a task. A popup should display the title, description, deadline, status, type and the person who’s assigned the task.
You can modify the title, description, deadline, status, type and assigned person of the task. Doing so is easy. Click on a task and you’ll have the
To delete a task, simply click on the trash icon at the bottom right hand side of the task menu. A confirmation modal should be displayed before the task is deleted.
As a user, you’ll want to create a relationship between two tasks. A relationship should have the following type:
blocks`/`blocked_by`,`parent_of`/`child_of
Or
related
At some point you’ll probably want to delete a relationship. No confirmation modal should be displayed before the task is deleted.
Projects are stored relationally in PostgreSQL. A project has the following properties:
id: User identifier
user: Owner of the project
name: Human readable name of the project
The project is linked to a graph (using id as graph name) A graph has many tasks.
Tasks are stored as nodes in Redis Graph. A task is a graph node and has the following properties:
A task can be linked to many other tasks by relationships.
Relationships are stored as edges in Redis Graph. A relationship is a directed graph edge and has the following properties:
from: Source node
type: One of
Blocked By
Child Of
Related To
to: Destination node
Relationships are stored as directed edges, but in the interface both directions are rendered. For example, if Task A is blocked by Task B, Task B will be shown as “blocks Task A”. It’s also possible to add relationships in both directions.
A graph has many tasks, which are fetched using the following Redis Graph query:
"GRAPH.QUERY" "055616f0-a130-42b1-a3fd-81b7c8a3ef1b" "MATCH (n:Task) RETURN n" "--compact"
A task is created and updated with all its properties using the following query:
"GRAPH.QUERY" "055616f0-a130-42b1-a3fd-81b7c8a3ef1b" "MERGE (n:Task {id: 'f5ec1f25-0cee-49d0-9a85-1043f04ea845'}) SET n.created_at = '2021-05-15 10:20:28 UTC', n.updated_at = '2021-05-15 10:20:28 UTC', n.graph = '#<Graph name=055616f0-a130-42b1-a3fd-81b7c8a3ef1b>', n.id = 'f5ec1f25-0cee-49d0-9a85-1043f04ea845', n.title = 'Submit hackathon app', n.description = '<p>Description of my task</p>', n.deadline = '2021-05-15', n.status = 'todo', n.type = 'task', n.user_id = '25714246-be92-4d96-b1ce-cbb57aaf4747'" "--compact"
A task is deleted using the following query:
"GRAPH.QUERY" "055616f0-a130-42b1-a3fd-81b7c8a3ef1b" "MATCH (n:Task {id: 'f5ec1f25-0cee-49d0-9a85-1043f04ea845'}) DELETE n" "--compact"
A task’s related nodes are always queried based on relationship type. The related tasks are fetched using the following query:
"GRAPH.QUERY" "055616f0-a130-42b1-a3fd-81b7c8a3ef1b" "MATCH (n:Task {id: 'c9bc52a0-c436-499c-954c-da40e82f50b2'}) -[r:blocked_by]-> (m:Task) RETURN n, m, type(r) AS t" "--compact"
Two tasks are linked to each other using the following query:
"GRAPH.QUERY" "055616f0-a130-42b1-a3fd-81b7c8a3ef1b" "MATCH (n:Task {id: '1ad21814-69d7-47d0-a7bb-de678b86c653'}), (m:Task {id: '07427e6b-7bba-44e4-b967-8fb5ca098053'}) MERGE (n) -[r:blocked_by]-> (m)" "--compact"
Two tasks are unlinked from each other using the following query:
"GRAPH.QUERY" "055616f0-a130-42b1-a3fd-81b7c8a3ef1b" "MATCH (n:Task {id: '1ad21814-69d7-47d0-a7bb-de678b86c653'}) -[r:related_to]-> (m:Task) DELETE r" "--compact"
A DSL was built to accommodate and simplify graph persistence. Its functionality is to provide a small but robust interface that will be familiar to developers who are used to Active Record’s API. The main class that’s implementing this construction can be found at app/graph/dsl.rb.
Here’s an example of a query:
query = graph
.match(:n, from.class.name, id: from.id)
.to(:r, type)
.match(:m, to.class.name)
.delete(:r)
query.to_cypher
# => "MATCH (n:Task {id: 'c9bc52a0-c436-499c-954c-da40e82f50b2'}) -[r:blocked_by]-> (m:Task) DELETE r"
query.execute
# => []
Disconnected and hidden tasks are a threat to any organization looking to maximize efficiency and outgrow their competitors.
Managers who can leverage an application capable of providing a clear visualization of assignments and their relationships can be more organized, think linearly and make quicker decisions in high-pressure situations.
RedisGraph is a crucial component as it allows data to be transmitted efficiently whilst projecting a visualization of each task and their relationships.
If you want to learn more about this app you can visit it on the Redis Launchpad. And whilst you’re there, make sure to explore all of the other innovative applications that we have available for you.
Florian Dejonckheere
Florian is an experienced Ruby on Rails developer who works as a software engineer at NephroFlow.