My first Open Source contribution

Mark Kop - Sep 23 '19 - - Dev Community

If you've met me in a tech event, you might already know that I'm an active user of Habitica, a habit tracker that applies gamification into your life. It's been helping me to keep myself organized while providing the sensation of playing an MMORPG which is something that I'm very passionate.

My profile was created in 2014, but only in 2016 I've given a try. I've engaged some other friends and it worked pretty well for some time. I even had contributed to Habitica's Portuguese Wiki with translations.
A few months ago I came back to Habitica and today I'm a Front-End Developer, so it shouldn't be hard to contribute with some code.

GitHub logo HabitRPG / habitica

A habit tracker app which treats your goals like a Role Playing Game.

I've taken this good first issue and shared my progress in this post. Before started I was concerned about the main difficulties being setting up the development environment and working with VueJS (which was very curious since I've learned React)

Add "Firefox Chat Extension" to the Settings > API page #11042

Alys avatar
Alys posted on

The User Icon > Settings > API page contains a link to the Chrome Chat Extension. There should also be a link to the Firefox Chat Extension, which is at https://addons.mozilla.org/en-US/firefox/addon/habitica-chat-client-v2/

Both extensions do the same thing, the only difference being the browser they run on. Because of this, I think it would be most helpful if the same bullet-point entry was used for both extensions - that should make it obvious that you're not missing out on anything if you install only one of them. The bullet point line could read "Chrome Chat Extension and Firefox Chat Extension" and the paragraph under it could be changed to this:

"The Chat Extension for Habitica adds an intuitive chat box to all of habitica.com. It allows users to chat in the Tavern, their party, and any guilds they are in."

I'll leave this issue open as suggestion-discussion for a few days and then if there's no objections or changes to this approach, I'll change it help wanted. I'll mark it as good first issue since it will be ideal for a new contributor. EDIT: This is on hold while some changes are being made to the extension.

First Steps

In this first part, I simply followed this guide:
Habitica Wiki - Setting Up Habitica Locally on Linux

Since I already had Git, build-essentials, Node, npm and MongoDB installed, these were the commands I've run:

sudo npm install -g mocha 
git clone https://github.com/Markkop/habitica.git
cd habitica
git remote add upstream https://github.com/HabitRPG/habitica.git
cp config.json.example config.json
npm install
sudo service mongod start
npm start
npm run client:dev
Enter fullscreen mode Exit fullscreen mode

http://localhost:8080/static/home
Hurray, Habitica is running on my own machine!
The login page was a little bugged without texts, but as instructed clearing the cache fixed it.
Then I created a User and logged in.

Starting to change stuff

By following this guide we create a new git branch
Habitica Wiki - Using Your Local Install to Modify Habitica's Website and API

git fetch upstream
git checkout -b firefox-extension-link
Enter fullscreen mode Exit fullscreen mode

The main goal is to add a link in the Settings page, and we can find it at website/client/components/settings/api.vue.

Before any changes

This is what we want to change:

li
  a(target='_blank' href='https://chrome.google.com/webstore/detail/habitrpg-chat-client/hidkdfgonpoaiannijofifhjidbnilbb') {{ $t('chromeChatExtension') }}
  br
  | {{ $t('chromeChatExtensionDesc') }}
Enter fullscreen mode Exit fullscreen mode

But what kind of HTML is that? As hinted by <template lang="pug">, this is the Pug Pre-Processor that takes this code and outputs HTML. The same with SASS and CSS.

Cool, so we only have to change this text and add other link.
But the thing is: all texts are actually variables because internationalization. How to access $t('chromeChatExtension') or even how to have a single text variable with two links?

A good way out is asking for help in the Blacksmiths Guild, but looking somewhere for a similar situation also works.

By checking this api's webpage we can notice that right above there is this API Token Warning message.

api token warning message

that corresponds to this line in the code

p(v-html='$t("APITokenWarning", { hrefTechAssistanceEmail })')`
Enter fullscreen mode Exit fullscreen mode

And by searching for APITokenWarning inside the project, we can find how settings.json declare this kind of variable

"APITokenWarning": "If you need a new API Token (e.g., if you accidentally shared it), email <%= hrefTechAssistanceEmail %> with your User ID and current Token. Once it is reset you will need to re-authorise everything by logging out of the website and mobile app and by providing the new Token to any other Habitica tools that you use.",
Enter fullscreen mode Exit fullscreen mode

Therefore, with <%= hrefTechAssistanceEmail %>

Also, the hrefTechAssistanceEmail's value can be found in the following section

/// api.vue
...
const TECH_ASSISTANCE_EMAIL = "admin@habitica.com";

export default {
  data() {
    return {
      newWebhook: {
        url: ""
      },
      hrefTechAssistanceEmail: `<a href="mailto:${TECH_ASSISTANCE_EMAIL}">${TECH_ASSISTANCE_EMAIL}</a>`,
      showApiToken: false
    };
  }
}, ...
Enter fullscreen mode Exit fullscreen mode

And after some trying out, we find out the correct way to use directly:

{{ $t("APITokenWarning", { hrefTechAssistanceEmail: "myemail@lol.com" }) }}
Enter fullscreen mode Exit fullscreen mode

Actually...

Ok, cool. We could just create some constants with each link and use them as the example above. However, what if someday someone had to change these links? Perhaps changing the text string directly in the settings.json file would be easier.

Since this approach results in less code, we're going to use it instead.

We then change chromeChatExtension and chromeChatExtensionDesc to the following:

"chatExtension": "<a target='blank' href='https://chrome.google.com/webstore/detail/habitrpg-chat-client/hidkdfgonpoaiannijofifhjidbnilbb'>Chrome Chat Extension</a> and <a target='blank' href='https://addons.mozilla.org/en-US/firefox/addon/habitica-chat-client-v2/'>Firefox Chat Extension</a>",
"chatExtensionDesc": "The Chat Extension for Habitica adds an intuitive chat box to all of habitica.com. It allows users to chat in the Tavern, their party, and any guilds they are in.",
Enter fullscreen mode Exit fullscreen mode

And our extensions list ends up being

ul
  li
    a(target='_blank' href='https://www.beeminder.com/habitica') {{ $t('beeminder') }}
    br
    | {{ $t('beeminderDesc') }}
  li(v-html="$t('chatExtension')")
    br
    | {{ $t('chatExtensionDesc') }}
  li
    a(target='_blank' :href='`https://oldgods.net/habitica/habitrpg_user_data_display.html?uuid=` + user._id') {{ $t('dataTool') }}
    br
    | {{ $t('dataToolDesc') }}
  li(v-html="$t('otherExtensions')")
    | {{ $t('otherDesc') }}
Enter fullscreen mode Exit fullscreen mode

The problem

After changes

By checking manually, we notice that chatExtensionsDesc isn't being displayed. In fact, otherDesc text isn't appearing, even on live!

After some experimenting, it seems that when tags are being created with attributes such as li(v-html="$t('otherExtensions')"), their children tags aren't displayed. The solution is changing the child indentation so it appears just below.

(bug with Pug+Vue?)

The final code is

      ul
        li
          a(target='_blank' href='https://www.beeminder.com/habitica') {{ $t('beeminder') }}
          br
          | {{ $t('beeminderDesc') }}
        li(v-html="$t('chatExtension')")
        | {{ $t('chatExtensionDesc') }}
        li
          a(target='_blank' :href='`https://oldgods.net/habitica/habitrpg_user_data_display.html?uuid=` + user._id') {{ $t('dataTool') }}
          br
          | {{ $t('dataToolDesc') }}
        li(v-html="$t('otherExtensions')")
        | {{ $t('otherDesc') }}
Enter fullscreen mode Exit fullscreen mode

End result

Conclusion

Before starting the project I thought the main difficult would be setting the project's environment, but instructions were crystal clear and I hadn't any problem.
The interesting part is that I thought it would be very simple to add another link in a single line of text, but faced several possible solutions because of Vue-i18n Plugin's internationalization.
At first the initial approach made more sense, because api.vue would be the main file where someone would check for if they'd need to change a link.
However, by putting it in the settings.json links could be changed to different languages as well. And changing the code would be much simpler.
The learnings in this opportunity were having my first hands-on contact with Vue, discovering the existence of HTML's pre-processors such as Pug and creating a Pull Request to a big project already in production.

Add "Firefox Chat Extension" to the Settings > API page #11375

Fixes #11042

Changes

I've added Firefox Chat Extension's link, removed Chrome Chat Extension's description and added a description about the Chat Extension

Before: before

After: after

While working on it, I've also discovered a bug with Pug and/or Vue that whenever using the HTML tag with attribute such as li(v-html="$t('otherExtensions')"), its children wouldn't be displayed, as you can notice how the text description of "Other Extensions" doesn't appear.

The fix is not putting the text as child by fixing its indentation.

This is the final result:

final

PS: I've mistakenly changed settings.json indentation. Is there any problem?


UUID: 40387571-91ee-489e-960f-278bf8fd503a

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .