If you want to contribute to Lumeer, read this document in order to save both your time and the time of the developers who maintain this project.
The project is written in Typescript and based on Angular. You can get familiar with this framework many different ways but we recommend you these steps:
- Read official Angular tutorial Tour of Heroes
- Take Angular Crash Course on Udemy
The state management is ensured by Redux-like library NgRx. It is crucial to know the principles this library is based on since it is used heavily throughout the whole application. You can start with the following sources or read more up-to-date articles on Medium:
Some knowledge of SASS preprocessor and RxJS is also highly recommended.
Before you start working on this project, you will need to set up your Git repository properly. To do so, follow these steps:
- If you are not familiar with Git, read at least first 3 chapters of this book.
- Set up your Git by following these instructions.
- Fork Lumeer engine repository by following this guide.
Try to write clean code that is self-explaining and can be easily understood by others. If you are not good at it, read the following book:
Prettier and TSLint are run as a Git pre-commit hook in order to provide uniform code style and check code quality.
Prettier formats the code automatically so you do not need to worry about formatting your code at all. It is recommended to install Prettier extension for your IDE so the code is formatted every time you save a file.
TSLint checks your code for potential problems and asks you to fix them before committing your changes.
HTML code is not formatted by Prettier at the moment as it uses different code style. Try to put every attribute on a new line to make the code more readable.
If you use Visual Studio Code with Prettier extension and want to use IDE's internal formatter for HTML, you need to add the following line to your workspace settings:
"prettier.disableLanguages": ["angular", "html", "vue"],
Although it might seem like an easy task, designing components in a good way is always something between art and rocket science.
Try to avoid large components doing 10 different things and having hundreds of lines of source code. Such components are hard to maintain and error-prone since every change might introduce various side effects and cause many bugs.
Try to design new components as small as possible. Basically every visual element should be represented by its own component.
For example, when you need to display a list of items together with other things in your component, it should probably be done in a separate component. Based on how complicated those items are and what actions you need to do with every one of them, it might also be a good practise to use a new component for displaying a single item.
To check the bundle size use:
$ npx source-map-explorer dist/{sth}.bundle.js dist/{sth}.bundle.js.map
Before you create a new component, you should think about other parts of the application where it could potentially be used. But do not overcomplicate a simple component just because some hypothetical use case in the future.
Try to design clear component interfaces (@Input
and @Output
properties in Angular) but keep the number of interactions with its surroundings to a minimum.
Add the following license header at the beginning of every TypeScript file you add to Lumeer engine repository:
/*
* Lumeer: Modern Data Definition and Processing Platform
*
* Copyright (C) since 2017 Lumeer.io, s.r.o. and/or its affiliates.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
Look at How To Contribute wiki page describing the workflow of creating a pull request to our repositories.
Here are some Angular-specific recommendations when working on this project.
The application is meant to be accessible in various languages. Bear this in mind when adding or modifying any visual elements shown to users.
If you add a new visual element containing a text shown to a user (including text in attributes such as title
), make sure you add i18n
in order to enable translation of this text to other languages.
The examples of using i18n
attribute:
<button i18n="@@collection.delete.dialog.button.no">No</button>
<a title="Settings" i18n-title="@@menu.settings">...</a>
Put unique identifier of this text as the value of i18n
attribute prefixed by @@
.
It needs to be unique across the whole application.
Read Angular Internationalization Guide for more details.
If you need to translate nouns after numbers (which can have multiple forms in different languages) or different text based on some property, use ICU Message Format.
In its current version (4.4.4), Angular does not support ICU message format in attributes. Use this workaround to make it work. You can find some examples already using this technique in this project.
If you add or modify elements with i18n
, make sure you run the following command before creating a commit:
$ npm run i18n
It will generate a new version of messages.xlf
file in src/i18n
folder and merge the changes to the files for other languages (such as messages.cs.xlf
).
Preferably, you should also provide a translation to these languages by changing <target>
element content as well as removing its state="new"
attribute in each newly added translation unit.
If you do not speak those languages, ask maintainers for a translation when you send a pull-request.
$ npm install <package name> --save
And if possible download the types too.
$ npm install @types/<package name> --save
Then add the package to .angular-cli.json
under "scripts"
key to include it in Angular CLI compilation:
"scripts": [
"../node_modules/<path to module javascript>"
]
Also add the module to vendor.ts
for webpack compilation:
import '../node_modules/<path to module javascript>';
If the module provides any classes for use, declare their types in typings.d.ts
:
declare var <class name>: any;
Lastly add it to polyfill.ts
if for browser mapping the module to its name:
window['<class name>'] = require('../node_modules/<path to module javascript>');
You need to rebuild the project after the change in order for your package to be included:
npm run-script build
Create a new perspective in view/perspectives/<perspective name>
with its own code component and module.
The module needs to provide the perspective component:
declarations: [
<perspective component>
],
exports: [
<perspective component>
]
Add the perspective name and icon in the perspective.ts
file.
(You can find your icon in icon palette when choosing collection icon, and just copy its name)
In the view-controls.component.html
add the perspective to the selection of views in two places:
<span ...>{perspective, select, <your perspective name> {<displayed name>} graph {Graph} ...}</span>
and few lines below in <ng-container *ngFor="let perspective of perspectives()">
:
<span ...>{perspective, select, <your perspective name> {<displayed name>} graph {Graph} ...}</span>
Add it to view-routing.module.ts
to map perspective name to it's component:
{
path: Perspective.<your perspective name>,
component: <perspecive component>
},
If your perspective should not be visible at all times (like when it needs a selected collection).
Update canShowPerspective
in view-controls.component.ts
to reflect this constraint. And add a
isDisplayable()
check in your perspective to make sure, users won't be able to access it using URL.
Prefer using attributes allowing {{ }} binding, as it is easier to read and allows writing strings in template style:
[style.width]="{{ width }}px"
class="{{ myClass }}"
instead of
[ngStyle]="{width: width + 'px'}"
[ngClass]="{myClass: true}"
Prefer using routerLink
in Angular input binding way, as it checks for
module dependencies:
[routerLink]="['start', 'child']"
instead of
routerLink="/start/child"
Use exact values (16px
, 18px
, 30px
) for sizes, instead of
medium
, large
, x-large
to keep the look consistent no matter the
user's browser font size.
Prefer using SCSS variables, as it keeps the style consistent, readable, and easy to change:
color: $brand-success;
instead of
color: white;