+
+ );
+};
+
+export const globalTypes = {
+ header: {
+ name: "header",
+ description: "Show header in story",
+ defaultValue: "yes",
+ toolbar: {
+ items: ["no", "yes"],
+ },
+ },
+ menuEnabled: {
+ name: "menu enabled",
+ description: "The menu in the header is enabled",
+ defaultValue: "yes",
+ toolbar: {
+ items: ["no", "yes"],
+ },
+ },
+};
+
+addDecorator(withinAppContext);
+addDecorator(withQueryCache);
+addDecorator(withI18n);
diff --git a/.travis.yml b/.travis.yml
index 6b651088..15166b30 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,29 @@
language: node_js
-node_js:
-- 7.8.0
-script: npm run build --production
-
-before_deploy: tar -zcvf $TRAVIS_BUILD_DIR/lime-app-$TRAVIS_BRANCH.tar.gz build
-
-deploy:
- provider: releases
- api_key:
- secure: piqSk7MFmSFohAFFLqH8XLTTi825NIJgOVw+yeeDEjZcRV8prdGSTulvWrLF+94MKR/veIW1DC6F2n5ZOtgzrTRIy+BzRstI6T1Np+h2FO0cg6mBgXnc8zi2G9S5CSR/Y4R5S4JUooTz+Yu2GTldkxJnf5DLl0C62AA2UjQclgWYes10gzO0PlO8nMJe2KkZYrWZwEgBJp+aLFme80mwkPY4F6fq4GL3xYRNRSzPD4SG1Rdj8qe+YyExT/AXsiMUEde86Bqq4U1c8Eaglum7n6Y/SnKvt6I9vpp+eSw2vPGh+ruS2Qb38mAMY1juE7czPQ1Afg4mLenwCoz9YrV/uq5RTtg/+3IpReoygbcJKvB/oqPUNjjONr2xrI/SplkAnan/WC5UHW1sl0hRDLfIsgIE0XhJqmUISSsyxEHIAjExVq1Q7nZp3wbl33bDGz9JM6quMrKgSoLTPSy7UC7x5FzPNxGj9MsAcQtnwIxDXg95iYG6u2mmQqA5BlGPcNl4CT9CIWh0kljRZqrSACN8QSQGjam109pcRdP9LbBJ4QWu6DBqK7MeVcBt1rmZa4cm9cF2ufEkm6V9MZ7k6YS+7tqm8BOYaalu2Sv63mfcGaf3GqYkgoAyUQ4xImQgBdD3e+FoG0P5UUORLPDz7u1BQ9Hv6M2Kdyu2XphiKUHxedk=
- file: $TRAVIS_BUILD_DIR/lime-app-$TRAVIS_BRANCH.tar.gz
- skip_cleanup: true
- on:
- tags: true
+node_js: stable
+
+install: npm install
+
+stages:
+ - name: storybook
+ if: branch = develop
+
+jobs:
+ include:
+ - stage: tests
+ script: npm run test
+
+ - stage: build
+ script: npm run build:production
+ before_deploy: tar -zcvf $TRAVIS_BUILD_DIR/lime-app-$TRAVIS_BRANCH.tar.gz build
+ deploy:
+ provider: releases
+ api_key: $GITHUB_OAUTH_TOKEN
+ file: $TRAVIS_BUILD_DIR/lime-app-$TRAVIS_BRANCH.tar.gz
+ skip_clean: true
+ on:
+ tags: true
+ after_deploy:
+ - "./.ci/send_pull_request.sh"
+ - stage: storybook
+ script:
+ - npm run storybook:build
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 943b359c..74427b19 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,457 @@
-# Change Log
+# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+## [0.2.26](https://github.com/libremesh/lime-app/compare/v0.2.25...v0.3.0) (2024-04-03)
+
+
+### ⚠ BREAKING CHANGES
+
+* **dependencies:** upgrade `react-query` v2 to v4. Also migrate old storybook `@storybook/addon-knobs to` api to `@storybook/addon-controls`
+
+### Features
+
+* **docker:** Add docker for local dev ([ffa9876](https://github.com/libremesh/lime-app/commit/ffa987670fa6cc9c73f6454dec043b22bc9b736e))
+* **fbw:** show scans results https://github.com/libremesh/lime-app/pull/339
+* **nodejs:** upgrade .nvmrc to 20 ([48f415b](https://github.com/libremesh/lime-app/commit/48f415ba312bf4eb8e84eea687de1178df23f342))
+* **gh-action:** create actions to test, build and create a build package to test
+* **packages:** upgrade packages to latest versions
+* **packages:** typescript and tailwindcss support
+
+### Bug Fixes
+
+* **ci:** translations not present ([2127352](https://github.com/libremesh/lime-app/commit/2127352ba6ee690f562b652a0effa35e3d053851))
+* **fbw:** multiple fixes and migrate to react query
+* **lime-plugin-metrics:** multiple fixes
+* **lime-plugin-metrics:** refactor to react query ([a166cd6](https://github.com/libremesh/lime-app/commit/a166cd627d3bb7d1683156124addcdb462889e08))
+* **lime-plugin-rx:** multiple fixes
+* **lime-plugin-rx:** migrate to react query ([7118a73](https://github.com/libremesh/lime-app/commit/7118a73a1b443e1d7a7dcdf06632032bfcb5bbc6))
+* **node-admin:** voucher tests ([bdf1219](https://github.com/libremesh/lime-app/commit/bdf12196ae4eaba6682ba5dd4b7168ef413f2f64))
+* **tests:** multiple text fixing. See https://github.com/libremesh/lime-app/issues/359
+* **jest:** fix regular expression to find the tests files ([a9f57f2](https://github.com/libremesh/lime-app/commit/a9f57f2333ead426c1526a3a50b4c9eed2e11ba5))
+
+* **dependencies:** upgrade node dependencies ([5acd8ca](https://github.com/libremesh/lime-app/commit/5acd8ca3f3aa738c80807e24707c301dae0a7842))
+### [0.2.25](https://github.com/germanferrero/lime-app/compare/v0.2.24...v0.2.25) (2022-03-04)
+
+
+### Features
+
+* **hotspot:** add hotspot feature ([6f0355f](https://github.com/germanferrero/lime-app/commit/6f0355fc4af7f6a55198bed58d5957ff14ce7e02))
+* **node admin:** add Roaming AP config ([31c65d1](https://github.com/germanferrero/lime-app/commit/31c65d19389bfa237245db7de3b5467bc9364172))
+* **node-admin:** allow changing wifi password ([12d8492](https://github.com/germanferrero/lime-app/commit/12d849275cbed31dd885c156ebe629b693062b39))
+* **pirania:** adds interface for pirania based on new-pirania-api ([63476a2](https://github.com/germanferrero/lime-app/commit/63476a2561eed8e7531faba5a4699622cf363c3c))
+* pirania ui ([353ffd9](https://github.com/germanferrero/lime-app/commit/353ffd90ac946815fc30cc09ae5e658f7ef874af))
+* **portal editor:** add portal editor ([d95d4fb](https://github.com/germanferrero/lime-app/commit/d95d4fb993dd8601a43d0854ccc8a1d0b63cf291))
+
+
+### Bug Fixes
+
+* **login:** make form submit on enter ([f218c6b](https://github.com/germanferrero/lime-app/commit/f218c6bee093e5407b8662010081d31181a34106))
+* **login:** persist session after page refresh ([ee0d9d4](https://github.com/germanferrero/lime-app/commit/ee0d9d486d317c89afdb838c4cb29d3e70bbde3c))
+* **reboot-banner:** persist page refresh ([cee2800](https://github.com/germanferrero/lime-app/commit/cee28004b13ab21a53f475f3c5eda4f2fe53a388))
+* **subheader:** show only one banner at a time ([0bc37bc](https://github.com/germanferrero/lime-app/commit/0bc37bcd90ce57b7839f0c7aceb9603814eb0557))
+* **translations:** fix error in pt translation ([3640de1](https://github.com/germanferrero/lime-app/commit/3640de19b3614066be66f84829354132ea30ccfb))
+
+### [0.2.24](https://github.com/germanferrero/lime-app/compare/v0.2.23...v0.2.24) (2022-02-23)
+
+### Bug Fixes
+
+* **firmware:** display spinners in download from release ([a50d314](https://github.com/germanferrero/lime-app/commit/a50d3144703a7c213e0ed1e80993a6db1ee9e89c))
+
+### [0.2.23](https://github.com/germanferrero/lime-app/compare/v0.2.22...v0.2.23) (2022-02-21)
+
+### Bug Fixes
+* **translations:** fix error in pt translation ([3640de1](https://github.com/germanferrero/lime-app/commit/3640de19b3614066be66f84829354132ea30ccfb))
+
+### [0.2.22](https://github.com/germanferrero/lime-app/compare/v0.2.21...v0.2.22) (2022-02-21)
+
+* **pirania:** add portuguese translations ([63476a2](https://github.com/germanferrero/lime-app/commit/d005012fb9925c849591c7051c3150f9263ebeba))
+
+### [0.2.21](https://github.com/germanferrero/lime-app/compare/v0.2.20...v0.2.21) (2022-02-21)
+
+
+### Features
+
+* **hotspot:** add hotspot feature ([6f0355f](https://github.com/germanferrero/lime-app/commit/6f0355fc4af7f6a55198bed58d5957ff14ce7e02))
+* **node admin:** add Roaming AP config ([31c65d1](https://github.com/germanferrero/lime-app/commit/31c65d19389bfa237245db7de3b5467bc9364172))
+* **node-admin:** allow changing wifi password ([12d8492](https://github.com/germanferrero/lime-app/commit/12d849275cbed31dd885c156ebe629b693062b39))
+* **pirania:** adds interface for pirania based on new-pirania-api ([63476a2](https://github.com/germanferrero/lime-app/commit/63476a2561eed8e7531faba5a4699622cf363c3c))
+* pirania ui ([353ffd9](https://github.com/germanferrero/lime-app/commit/353ffd90ac946815fc30cc09ae5e658f7ef874af))
+* **portal editor:** add portal editor ([d95d4fb](https://github.com/germanferrero/lime-app/commit/d95d4fb993dd8601a43d0854ccc8a1d0b63cf291))
+
+
+### Bug Fixes
+
+* **getvoices:** fix synth voices crash in align screen ([1ba18c4](https://github.com/germanferrero/lime-app/commit/1ba18c4e0a0154a9568ae6e6a4d73e570f940c98))
+
+### [0.2.20](https://github.com/germanferrero/lime-app/compare/v0.2.19...v0.2.20) (2021-05-11)
+
+* **map:** prevent buttons overflow in mobile
+* **align:** show message "no mesh interfaces available" when there aren't
+### [0.2.19](https://github.com/germanferrero/lime-app/compare/v0.2.18...v0.2.19) (2021-05-11)
+
+
+### Bug Fixes
+
+* **firmware:** disable upgrade button after submit ([aaea467](https://github.com/germanferrero/lime-app/commit/aaea4670f064fbb07c6f35bc4ac5d47a6826a1cd))
+
+### [0.2.18](https://github.com/germanferrero/lime-app/compare/v0.2.17...v0.2.18) (2021-05-11)
+
+
+### Bug Fixes
+
+* **firmware:** show loading spinner while uploading file ([ea4293c](https://github.com/germanferrero/lime-app/commit/ea4293cbabf1d0c757114e441d2084518e00e3d6))
+
+### [0.2.17](https://github.com/germanferrero/lime-app/compare/v0.2.16...v0.2.17) (2021-05-06)
+
+
+### Features
+
+* **translations:** add a lot of pt-br translations :)
+* **menu:** add community / node view to menu (currently without community features) ([09fcec8](https://github.com/germanferrero/lime-app/commit/09fcec8e5872e27e6adfad0ba1a6e23c14efdb2e))
+
+
+### Bug Fixes
+
+* **translations:** fix English counts ([8b3d0c4](https://github.com/germanferrero/lime-app/commit/8b3d0c4f0998f9b1e77ba2e085b6b8ef082c83e3))
+* **translations:** fix English spelling ([a319694](https://github.com/germanferrero/lime-app/commit/a3196940452fa21de63c9928ee3017b4a1f60cd0))
+* **translations:** force lowercase locale to I18n ([34e7b57](https://github.com/germanferrero/lime-app/commit/34e7b57a7dc6edf58f9ef769ff02f3dc0a64f32c))
+* **translations:** spelling fixes for pt-br ([11d52b8](https://github.com/germanferrero/lime-app/commit/11d52b894dc9404c380622d74adf44b77fc1944f))
+* **upgrade:** fix typo, now showing release link to more info ([14e6f89](https://github.com/germanferrero/lime-app/commit/14e6f89e81c15b41707b7cea0d13b180e0d0c8ff))
+
+### [0.2.16](https://github.com/germanferrero/lime-app/compare/v0.2.15...v0.2.16) (2021-03-12)
+
+
+### Bug Fixes
+
+* **align:** url incremental growth at align-single ([3f92f6a](https://github.com/germanferrero/lime-app/commit/3f92f6a5079143c1b6478b0d1ab3483076d642db))
+* **firmware:** fix firmware upgrade when eupgrade is missing ([f6683af](https://github.com/germanferrero/lime-app/commit/f6683af2a36c33a9d67a43824a46d8eb419667f1))
+* **i18n:** fix localization fallback. Bring back some PT-br translations([4891d66](https://github.com/germanferrero/lime-app/commit/4891d666c810623980c36d6ee2dae32a6462a8d3))
+* **remotesupport:** fix remotesupport broken ui when no internet ([a198536](https://github.com/germanferrero/lime-app/commit/a19853687e21aef94b3809ff4155e07a28a1f958))
+
+### Improvements
+
+* **changenode:** improve UI texts with more user-friendly ones ([cab16f3](https://github.com/libremesh/lime-app/commit/cab16f3bbcf54b30f906e065ac569810e8b509a1))
+### [0.2.15](https://github.com/germanferrero/lime-app/compare/v0.2.14...v0.2.15) (2021-01-27)
+
+
+### Bug Fixes
+
+* **most_active:** fix rx page not loading when no most_active ([428f267](https://github.com/germanferrero/lime-app/commit/428f2670e8a89f6de7f1254129a23ce72988b37f))
+
+### [0.2.14](https://github.com/germanferrero/lime-app/compare/v0.2.13...v0.2.14) (2021-01-27)
+
+### Refactor
+* **bathost:** adapt to new ubus endpoint
+
+### [0.2.13](https://github.com/germanferrero/lime-app/compare/v0.2.12...v0.2.13) (2021-01-25)
+
+### Features
+* **remotesupport:** add support for sharing tmate sessions to your node ([#289](https://github.com/libremesh/lime-app/pull/289))
+
+### Bug Fixes
+
+* **map:** load community when this node is not in nodes_and_links db ([67140b3](https://github.com/germanferrero/lime-app/commit/67140b31efa34b8c3817b84a42d36cebeadab262))
+
+### Improvements
+* **map:** show links only when both nodes list each other as associated ([d195ac4](https://github.com/germanferrero/lime-app/commit/9038906ff7f3de5b6a4758e739705c3c7d195ac4))
+
+### [0.2.12](https://github.com/germanferrero/lime-app/compare/v0.2.11...v0.2.12) (2021-01-15)
+### Features
+* **align** New align screen, check out more info at PR [#285](https://github.com/libremesh/lime-app/pull/285)
+
+### [0.2.11](https://github.com/libremesh/lime-app/compare/v0.2.10...v0.2.11) (2020-11-27)
+
+
+### Features
+
+* **firstbootwizard:** add do not ask again option to fbw banner ([ed9b733](https://github.com/libremesh/lime-app/commit/ed9b73388fe610358f7db52ab2ebabdc3b0d8676))
+
+* **firmware upgrade:** add one click firmware upgrade ([a62547d](https://github.com/libremesh/lime-app/commit/a62547d971438cf3197f40432708469b410eca94))
+
+### Bug Fixes
+
+* **firstbootwizard:** ask root privilege to run fbw ([4c5e52e](https://github.com/libremesh/lime-app/commit/4c5e52e7d25d2e146e8a973a7ca64fdb3e9f9961))
+
+### [0.2.10](https://github.com/germanferrero/lime-app/compare/v0.2.9...v0.2.10) (2020-10-29)
+
+
+### Bug Fixes
+
+* **fbw:** fix app crash when lime-fbw is not available ([8993892](https://github.com/germanferrero/lime-app/commit/8993892334dbdd52c7804dda4d63ff22be4ef276))
+* **fbw:** protect fbw with root password ([3930f1e](https://github.com/germanferrero/lime-app/commit/3930f1eb80caea0904cacbc755dba5e437f6832c))
+
+### [0.2.9](https://github.com/germanferrero/lime-app/compare/v0.2.8...v0.2.9) (2020-09-16)
+
+### [0.2.8](https://github.com/germanferrero/lime-app/compare/v0.2.7...v0.2.8) (2020-09-16)
+
+### [0.2.6](https://github.com/germanferrero/lime-app/compare/v0.2.5...v0.2.6) (2020-09-15)
+
+
+### Features
+
+* **firmware upgrade:** basic implementation of firmware upgrade ([175ec82](https://github.com/germanferrero/lime-app/commit/175ec820aab261463c13318b30bc1ff687467bf4))
+
+
+### Bug Fixes
+
+* **fbw:** allow uppercase letters in network name ([987c458](https://github.com/germanferrero/lime-app/commit/987c4581d350e3cc75b2e467e1559748e870f2fc))
+* **rx:** fix most_active change node functionality ([acc2617](https://github.com/germanferrero/lime-app/commit/acc26176da225501c6d02c8403bede54d270cefb))
+* **rxpage:** fix uptime days field ([85e6b55](https://github.com/germanferrero/lime-app/commit/85e6b5562585c69652a08f2e828e57181cc543e1))
+* **shared-password:** do not show success message on error ([3866041](https://github.com/germanferrero/lime-app/commit/38660416dbb6391b0e338c0f128e52dd57828bcd))
+
+### [0.2.5](https://github.com/germanferrero/lime-app/compare/v0.2.4...v0.2.5) (2020-05-20)
+
+
+### CI Changes
+
+* **libremesh pull request** overwrite master Makefile, no template one ([eb4fe08](https://github.com/germanferrero/lime-app/commit/eb4fe08815af15f68fee222263bd151bff79744c))
+
+### [0.2.4](https://github.com/germanferrero/lime-app/compare/v0.2.2...v0.2.4) (2020-05-20)
+
+
+### Features
+
+* **fbw:** add shared password to network creation form ([0e90457](https://github.com/germanferrero/lime-app/commit/0e90457f828e84264ded5568205925d57ef82918)), closes [#237](https://github.com/germanferrero/lime-app/issues/237)
+* **plugin-network-admin:** add network admin plugin ([b40604c](https://github.com/germanferrero/lime-app/commit/b40604c1bae0ed8d65d1c01ddd63e8b791390d94))
+
+
+### Bug Fixes
+
+* **locate:** fix ui bugs related to undefined coordinates of nodes ([d6e90d5](https://github.com/germanferrero/lime-app/commit/d6e90d5f0bd2e205731836daf3312e29c9d391bc)), closes [#250](https://github.com/germanferrero/lime-app/issues/250)
+
+### [0.2.3](https://github.com/libremesh/lime-app/compare/v0.2.2...v0.2.3) (2020-02-11)
+
+
+### Bug Fixes
+
+* **bug:** fix access from different node ([956b337](https://github.com/libremesh/lime-app/commit/956b337048b640062fdc975b74a74f605bbe0b52))
+
+### [0.2.2](https://github.com/libremesh/lime-app/compare/v0.2.1...v0.2.2) (2020-01-29)
+
+
+### Features
+
+* **rxjs:** update to new api in epics and api files ([8500cc5](https://github.com/libremesh/lime-app/commit/8500cc5664834c73eb539d0b1ee8f3b1eb22b4d5))
+
+
+### Bug Fixes
+
+* **align:** fix setInterval and redux state ([a430c69](https://github.com/libremesh/lime-app/commit/a430c69152728dba60c324cea47dfc3225496f3c))
+* **bug:** 10.5.0.1 as home address ([58f581d](https://github.com/libremesh/lime-app/commit/58f581da78a1479bc160c40cfeb5793fe138c34d))
+* **intl:** fix int18n errors and add new translations ([c3dc4bb](https://github.com/libremesh/lime-app/commit/c3dc4bb425c5f49a4cfeb52c39416d56028e7268))
+* **navigation:** avoid undefined elements ([1814c39](https://github.com/libremesh/lime-app/commit/1814c39ebe49edd3e1f817d7d9836632709772af))
+* **timer:** fix uptime timer ([214f83a](https://github.com/libremesh/lime-app/commit/214f83a1a53eea704ddfed4f28eb87166d5c651e))
+* **timer:** fix uptime timer ([21b3e2e](https://github.com/libremesh/lime-app/commit/21b3e2ed6a7b38b37a02e2b3f3db730c670bf73c))
+
+### [0.2.1](https://github.com/libremesh/lime-app/compare/v0.2.0...v0.2.1) (2019-10-22)
+
+
+### Bug Fixes
+
+* **fbw:** community name in lowercase ([73d464e](https://github.com/libremesh/lime-app/commit/73d464e))
+* **slugify:** improves domain usage ([0237be9](https://github.com/libremesh/lime-app/commit/0237be9))
+* **validation:** fix hostname and communiy name validation in fbw ([436a258](https://github.com/libremesh/lime-app/commit/436a258))
+* **validation:** fix hostname validation in adminPage ([13afd8c](https://github.com/libremesh/lime-app/commit/13afd8c))
+
+
+### Features
+
+* **redux:** add generic actions file ([fb4f173](https://github.com/libremesh/lime-app/commit/fb4f173))
+* **validation:** hostname validation and slugify ([48cdd4e](https://github.com/libremesh/lime-app/commit/48cdd4e))
+
+## [0.2.0](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.13...v0.2.0) (2019-10-08)
+
+
+### Bug Fixes
+
+* **config:** remove duplicated hostname ([0cd3ac9](https://github.com/libremesh/lime-app/commit/0cd3ac9)), closes [#207](https://github.com/libremesh/lime-app/issues/207)
+* **redirect:** full redirect instead of change the api endopint ([5dd520e](https://github.com/libremesh/lime-app/commit/5dd520e))
+* **redirect:** remove redirect on metrics page ([6639b64](https://github.com/libremesh/lime-app/commit/6639b64))
+* **validation:** network and host name validation in FBW ([85755ef](https://github.com/libremesh/lime-app/commit/85755ef))
+
+
+# [0.2.0-alpha.13](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.12...v0.2.0-alpha.13) (2019-06-25)
+
+
+### Bug Fixes
+
+* **metrics:** fix error messages on gateway error ([858bf02](https://github.com/libremesh/lime-app/commit/858bf02))
+
+
+### Features
+
+* **metrics:** change to new lime-metrics response ([7131d02](https://github.com/libremesh/lime-app/commit/7131d02))
+
+
+
+
+# [0.2.0-alpha.12](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.11...v0.2.0-alpha.12) (2019-06-25)
+
+
+### Bug Fixes
+
+* **location:** catch error loading nodes links ([a255d9c](https://github.com/libremesh/lime-app/commit/a255d9c))
+* **location:** fix comparation. Convert all values to number ([f47da3a](https://github.com/libremesh/lime-app/commit/f47da3a))
+* **location:** fix geojson render ([6b90dc6](https://github.com/libremesh/lime-app/commit/6b90dc6))
+* **location:** remove develop ip in meta/CONECTION_START event ([12c3a92](https://github.com/libremesh/lime-app/commit/12c3a92))
+* **package:** update axios to version 0.19.0 ([27401f9](https://github.com/libremesh/lime-app/commit/27401f9))
+
+
+### Features
+
+* **location:** include hostname in point data ([f3c4ead](https://github.com/libremesh/lime-app/commit/f3c4ead))
+
+
+
+
+# [0.2.0-alpha.6](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.5...v0.2.0-alpha.6) (2019-03-09)
+
+
+### Bug Fixes
+
+* change api error message ([033c5d9](https://github.com/libremesh/lime-app/commit/033c5d9)), closes [#113](https://github.com/libremesh/lime-app/issues/113)
+* first boot wizard screen ([46069ef](https://github.com/libremesh/lime-app/commit/46069ef))
+* metrics on gateway node ([3fead9f](https://github.com/libremesh/lime-app/commit/3fead9f)), closes [#112](https://github.com/libremesh/lime-app/issues/112)
+
+
+
+
+# [0.2.0-alpha.5](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.3...v0.2.0-alpha.5) (2019-02-25)
+
+
+
+
+# [0.2.0-alpha.4](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.3...v0.2.0-alpha.4) (2019-02-25)
+
+
+
+
+# [0.2.0-alpha.3](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.0...v0.2.0-alpha.3) (2019-02-25)
+
+
+### Bug Fixes
+
+* **fbw:** change fbw api ([696fc98](https://github.com/libremesh/lime-app/commit/696fc98))
+* **fbw:** remove groundrouting plugin and add fbw ([cb5711d](https://github.com/libremesh/lime-app/commit/cb5711d))
+* **redux:** fbw catch must return an array ([b8d34e2](https://github.com/libremesh/lime-app/commit/b8d34e2))
+* **redux-observable:** update epics to redux-ovservable 1.0 ([a8a9234](https://github.com/libremesh/lime-app/commit/a8a9234))
+
+
+### Features
+
+* **component:** add global banner component ([154568a](https://github.com/libremesh/lime-app/commit/154568a))
+* **fbw:** add firstbootwizard page ([8157a0d](https://github.com/libremesh/lime-app/commit/8157a0d))
+* **fbw:** init first boot wizard ([905b552](https://github.com/libremesh/lime-app/commit/905b552))
+
+
+
+
+# [0.2.0-alpha.2](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.0...v0.2.0-alpha.2) (2019-02-25)
+
+
+### Bug Fixes
+
+* **fbw:** change fbw api ([696fc98](https://github.com/libremesh/lime-app/commit/696fc98))
+* **fbw:** remove groundrouting plugin and add fbw ([cb5711d](https://github.com/libremesh/lime-app/commit/cb5711d))
+* **redux:** fbw catch must return an array ([b8d34e2](https://github.com/libremesh/lime-app/commit/b8d34e2))
+* **redux-observable:** update epics to redux-ovservable 1.0 ([a8a9234](https://github.com/libremesh/lime-app/commit/a8a9234))
+
+
+### Features
+
+* **component:** add global banner component ([154568a](https://github.com/libremesh/lime-app/commit/154568a))
+* **fbw:** add firstbootwizard page ([8157a0d](https://github.com/libremesh/lime-app/commit/8157a0d))
+* **fbw:** init first boot wizard ([905b552](https://github.com/libremesh/lime-app/commit/905b552))
+
+
+
+
+# [0.2.0-alpha.1](https://github.com/libremesh/lime-app/compare/v0.2.0-alpha.0...v0.2.0-alpha.1) (2019-02-25)
+
+
+### Bug Fixes
+
+* **fbw:** change fbw api ([696fc98](https://github.com/libremesh/lime-app/commit/696fc98))
+* **fbw:** remove groundrouting plugin and add fbw ([cb5711d](https://github.com/libremesh/lime-app/commit/cb5711d))
+* **redux:** fbw catch must return an array ([b8d34e2](https://github.com/libremesh/lime-app/commit/b8d34e2))
+* **redux-observable:** update epics to redux-ovservable 1.0 ([a8a9234](https://github.com/libremesh/lime-app/commit/a8a9234))
+
+
+### Features
+
+* **component:** add global banner component ([154568a](https://github.com/libremesh/lime-app/commit/154568a))
+* **fbw:** add firstbootwizard page ([8157a0d](https://github.com/libremesh/lime-app/commit/8157a0d))
+* **fbw:** init first boot wizard ([905b552](https://github.com/libremesh/lime-app/commit/905b552))
+
+
+
+
+# [0.2.0-alpha.0](https://github.com/libremesh/lime-app/compare/v0.1.1-alpha.0...v0.2.0-alpha.0) (2018-10-24)
+
+
+### Bug Fixes
+
+* **location:** fix inverted value in default location ([6fac5dd](https://github.com/libremesh/lime-app/commit/6fac5dd))
+
+
+### Features
+
+* **align:** show message when no other node is found ([84a2c1b](https://github.com/libremesh/lime-app/commit/84a2c1b))
+
+
+
+
+## [0.1.1-alpha.0](https://github.com/libremesh/lime-app/compare/v0.1.0-alpha.5...v0.1.1-alpha.0) (2018-10-23)
+
+
+### Bug Fixes
+
+* **husky:** update hooks in package.json ([87ac1ba](https://github.com/libremesh/lime-app/commit/87ac1ba))
+* **path:** change default path to libremesh lime-app path ([53106c0](https://github.com/libremesh/lime-app/commit/53106c0))
+
+
+
+
+# [0.1.0](https://github.com/libremesh/lime-app/compare/v0.1.0-alpha.5...v0.1.0) (2018-10-23)
+
+
+### Bug Fixes
+
+* **husky:** update hooks in package.json ([87ac1ba](https://github.com/libremesh/lime-app/commit/87ac1ba))
+* **path:** change default path to libremesh lime-app path ([53106c0](https://github.com/libremesh/lime-app/commit/53106c0))
+
+
+
+
+# [0.1.0-alpha.5](https://github.com/libremesh/lime-app/compare/v0.1.0-alpha.4...v0.1.0-alpha.5) (2018-10-23)
+
+
+### Bug Fixes
+
+* **api:** fix api call ([00dc926](https://github.com/libremesh/lime-app/commit/00dc926))
+* **cors:** fix cors connection ([13ef9b5](https://github.com/libremesh/lime-app/commit/13ef9b5))
+* **groundrouting:** disable groundrouting plugin ([e792737](https://github.com/libremesh/lime-app/commit/e792737))
+* **package:** update leaflet.gridlayer.googlemutant to version 0.7.0 ([5be94dd](https://github.com/libremesh/lime-app/commit/5be94dd))
+* **package:** update redux-observable to version 0.19.0 ([a941dce](https://github.com/libremesh/lime-app/commit/a941dce))
+* **package:** update redux-observable to version 1.0.0-beta.2 ([667aa46](https://github.com/libremesh/lime-app/commit/667aa46))
+* **reducer:** fix wrong state variable ([49edbcb](https://github.com/libremesh/lime-app/commit/49edbcb))
+* **redux:** use new redux-observable api ([f916d61](https://github.com/libremesh/lime-app/commit/f916d61))
+* **transaltion:** fix metrics page transaltions ([07969ad](https://github.com/libremesh/lime-app/commit/07969ad))
+* **translations:** remove preact-inline from status component ([7668701](https://github.com/libremesh/lime-app/commit/7668701))
+* **url:** fix ground routing url in menu ([78a8263](https://github.com/libremesh/lime-app/commit/78a8263))
+
+
+### Features
+
+* **loading:** add loading in ground routing page ([1d92b0f](https://github.com/libremesh/lime-app/commit/1d92b0f))
+* **location:** add new ubus-lime-location api ([a32622b](https://github.com/libremesh/lime-app/commit/a32622b))
+* **location:** detect unassigned location in node ([e0678a9](https://github.com/libremesh/lime-app/commit/e0678a9))
+* **plugin:** init ground routing script ([442e934](https://github.com/libremesh/lime-app/commit/442e934))
+* **plugin:** register groundrouting plugin in config.js ([1688639](https://github.com/libremesh/lime-app/commit/1688639))
+
+
+
# [0.1.0-alpha.4](https://github.com/libremesh/lime-app/compare/v0.1.0-alpha.3...v0.1.0-alpha.4) (2018-02-06)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e7db9ec2..d065bef8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -167,6 +167,68 @@ If you have a Pull Request already pending, GitHub should pick up the recent
changes and indicate that the PR is ready to be merged.
+### Contributing with translations
+This guide describe how to contribute with translating LimeApp interface texts to different languages
+creating a Pull Request with modifications of the corresponding translation files.
+Please first follow "Forks and Pull Requests" topic above to know how to come up with a well formed Pull Request.
+Once you have setup your fork please do:
+
+```npm install```
+
+To update dependendencies. And then
+
+```npm run translations:extract```
+
+This will create a messages.po for each locale under i18n/{locale}/ and print statistics of total/missing translations for each of the supported locales:
+
+```
+Catalog statistics for i18n/{locale}/messages:
+┌─────────────┬─────────────┬─────────┐
+│ Language │ Total count │ Missing │
+├─────────────┼─────────────┼─────────┤
+│ es │ 191 │ 0 │
+│ pt │ 191 │ 23 │
+│ en (source) │ 191 │ - │
+│ it │ 191 │ 171 │
+└─────────────┴─────────────┴─────────┘
+```
+
+If the locale you are willing to add is not there, please add it to `.linguirc` in `locales` field.
+
+There are lot of desktop/online tools to edit .po files. [poedit](https://poedit.net/) is one of them, available in apt package manager: `sudo apt install poedit`.
+
+Some translations involve variable data interpolation like this one:
+```
+"{versionName} is now available",
+```
+Wich you should be translated like this (in spanish):
+```
+"{versionName} ya está disponible",
+```
+
+Others involve pluralization like this one:
+```
+{hours, plural, one {# hour} other {# hours}}
+```
+Which you should be translated like this (in spanish):
+```
+{hours, plural, one {# hora} other {# horas}}
+```
+
+Once you have completed all translation you can run again
+
+`npm run translations:extract`
+
+to check that there are no missing keys for the targeted language. And create the Pull Request (including modifications to .po files).
+
+If you need more context to understand how to translate some key you can checkout the demo screens at storybook with:
+
+```npm run storybook```
+
+And findout how is that key used in the LimeApp.
+Also, do not hesitate to contact developers directly :)
+
+
### More Information
For more information, please see [Collaborating on projects using issues and pull requests](https://help.github.com/categories/collaborating-on-projects-using-issues-and-pull-requests/) in the GitHub help guide.
@@ -241,4 +303,4 @@ members of the project's.
Adapted from [contributor-covenant.org](http://contributor-covenant.org/version/1/4)
[semantic-release]: https://npmjs.com/package/semantic-release
-[convention]: https://github.com/conventional-changelog/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md
\ No newline at end of file
+[convention]: https://github.com/conventional-changelog/conventional-changelog-angular/blob/ed32559941719a130bb0327f886d6a32a8cbc2ba/convention.md
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 00000000..0ba71526
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,10 @@
+FROM node:18-alpine
+
+WORKDIR /app
+
+COPY package* /app/
+RUN npm i
+
+RUN mkdir node_modules/.cache && chmod -R 777 node_modules/.cache
+
+EXPOSE 8080
diff --git a/LICENSE b/LICENSE
index 9cecc1d4..dba13ed2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
@@ -7,17 +7,15 @@
Preamble
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
+our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
+software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
@@ -26,44 +24,34 @@ them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
The precise terms and conditions for copying, distribution and
modification follow.
@@ -72,7 +60,7 @@ modification follow.
0. Definitions.
- "This License" refers to version 3 of the GNU General Public License.
+ "This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
@@ -549,35 +537,45 @@ to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
- 13. Use with the GNU Affero General Public License.
+ 13. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
+under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
+the GNU Affero General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
+Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
+GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
+versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
@@ -631,44 +629,33 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
- {one line to give the program's name and a brief idea of what it does.}
- Copyright (C) {year} {name of author}
+
+ Copyright (C)
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
+ it under the terms of the GNU Affero 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.
+ GNU Affero General Public License for more details.
- You should have received a copy of the GNU General Public License
+ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- {project} Copyright (C) {year} {fullname}
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
+For more information on this, and how to apply and follow the GNU AGPL, see
.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
diff --git a/README.md b/README.md
index 6733dfd8..830d7083 100644
--- a/README.md
+++ b/README.md
@@ -1,64 +1,74 @@
# LiMeApp
-[![Greenkeeper badge](https://badges.greenkeeper.io/libremesh/lime-app.svg)](https://greenkeeper.io/) [![Build Status](https://travis-ci.org/libremesh/lime-app.svg?branch=develop)](https://travis-ci.org/libremesh/lime-app) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
-
-**Simple, lightweight and scalable PWA for diagnosis of Libremesh nodes**
+[![Greenkeeper badge](https://badges.greenkeeper.io/libremesh/lime-app.svg)](https://greenkeeper.io/) [![Build Status](https://travis-ci.org/libremesh/lime-app.svg?branch=develop)](https://travis-ci.org/libremesh/lime-app) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
+> Geek-free Web App for setup and mantainance of Libremesh nodes built on Preact
+ );
+}
+
+export default ${componentName};
+`;
+};
+
+const queriesContent = (name) =>
+ `// Here you define queries and mutations which connects the api with your components
+import { useQuery, useMutation } from '@tanstack/react-query';
+import { getSomething } from './${name}Api';
+
+export const useSomething = () => useQuery(['package', 'command'], getSomething);
+`;
+
+const apiContent = () =>
+ `// Here you define the api calls to the ubus uhttpd enpoints your plugin needs
+import api from 'utils/uhttpd.service';
+
+export const getSomething = () => api.call('package', 'command', {});
+`;
+
+const apiSpecContent = (name) =>
+ `// Here you define unit tests for the api endpoints of this plugin
+import { getSomething } from './${name}Api'
+import api from 'utils/uhttpd.service';
+import { of } from 'rxjs';
+jest.mock('utils/uhttpd.service')
+
+beforeEach(() => {
+ api.call.mockImplementation(() => of({status: 'ok'}))
+})
+
+describe('getSomething', () => {
+ it('test some behaviour', async () => {
+ expect(true).toBeTrue();
+ });
+ it('test some other behaviour', async () => {
+ expect(true).toBeTrue();
+ });
+});
+`;
+
+const specContent = (name) => {
+ const componentName = name.charAt(0).toUpperCase() + name.slice(1);
+ return `// Here you define tests that closely resemble how your component is used
+// Using the testing-library: https://testing-library.com
+
+import { screen, cleanup, act } from '@testing-library/preact';
+import '@testing-library/jest-dom';
+import { render } from 'utils/test_utils';
+import queryCache from 'utils/queryCache';
+
+import ${componentName} from './src/${name}Page';
+import { getSomething } from './src/${name}Api';
+
+jest.mock('./src/${name}Api');
+
+describe('${name}', () => {
+ beforeEach(() => {
+ getSomething.mockImplementation(async () => "something");
+ });
+
+ afterEach(() => {
+ cleanup();
+ act(() => queryCache.clear());
+ });
+
+ it('test that something is shown', async() => {
+ render(<${componentName} />);
+ expect(await screen.findByText('something')).toBeInTheDocument();
+ })
+});
+`;
+};
+
+const storiesContent = (name, menuName) => {
+ const componentName = name.charAt(0).toUpperCase() + name.slice(1);
+ return `//Here you define the StoryBook stories for this plugin
+
+import ${componentName} from './src/${name}Page';
+
+export default {
+ title: 'Containers/${menuName || name}'
+}
+
+export const myStory = () => <${componentName} />
+`;
+};
+
+const styleContent = () => "// Here you define the css for this plugin";
+
+yargs(hideBin(process.argv))
+ .command(
+ "$0 create ",
+ "create an skeleton for a new plugin",
+ (yargs) =>
+ yargs
+ .positional("name", {
+ describe:
+ "the name of your plugin without lime-plugin suffix",
+ })
+ .option("protected", {
+ alias: "p",
+ type: "boolean",
+ default: false,
+ describe: "whether it is protected by shared password",
+ })
+ .option("menu-name", {
+ alias: "m",
+ type: "string",
+ describe: "name for the menu entry. Default to plugin name",
+ }),
+ create
+ )
+ .help().argv;
+
+function create(argv) {
+ const name = argv.name;
+ const pluginName = `lime-plugin-${name}`;
+ const baseDir = path.join(__dirname, "..", "plugins", pluginName);
+ fs.mkdirSync(baseDir);
+ fs.mkdirSync(path.join(baseDir, "src"));
+ fs.writeFileSync(
+ path.join(baseDir, "src", `${name}Page.js`),
+ pageContent(name)
+ );
+ fs.writeFileSync(
+ path.join(baseDir, "src", `${name}Queries.js`),
+ queriesContent(name)
+ );
+ fs.writeFileSync(path.join(baseDir, "src", `${name}Api.js`), apiContent());
+ fs.writeFileSync(
+ path.join(baseDir, "src", `${name}Api.spec.js`),
+ apiSpecContent(name)
+ );
+ fs.writeFileSync(
+ path.join(baseDir, "src", `${name}Menu.js`),
+ menuContent(name, argv.menuName)
+ );
+ fs.writeFileSync(
+ path.join(baseDir, "src", `${name}Style.less`),
+ styleContent()
+ );
+ fs.writeFileSync(
+ path.join(baseDir, "index.js"),
+ indexContent(name, argv.protected)
+ );
+ fs.writeFileSync(path.join(baseDir, `${name}.spec.js`), specContent(name));
+ fs.writeFileSync(
+ path.join(baseDir, `${name}.stories.js`),
+ storiesContent(name)
+ );
+ const configPath = path.join(__dirname, "..", "src", "config.js");
+ console.log(
+ `You are done. Remember to add ${name} to the list in ${configPath}`
+ );
+}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 00000000..510baea4
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,17 @@
+version: '3.7'
+
+services:
+ ui:
+ build: ./
+ command: sh -c "npm run dev & npm run storybook"
+ environment:
+ - NODE_OPTIONS=--openssl-legacy-provider
+ volumes:
+ - ./:/app
+ - node_modules:/app/node_modules
+ ports:
+ - 8080:8080
+ - 8081:8081
+
+volumes:
+ node_modules:
diff --git a/docs/Tutorial.md b/docs/Tutorial.md
new file mode 100644
index 00000000..8c286f1f
--- /dev/null
+++ b/docs/Tutorial.md
@@ -0,0 +1,539 @@
+# LimeApp's Developer Tutorial
+Wellcome, this the developer tutorial for LimeApp developers!
+
+## What do I need to know to collaborate in the LimeApp?
+
+The LimeApp is written in Javascript, HTML and CSS.
+Having a basic knowledge of these languages will help you to collaborate in the in the development. You can follow these resources to learn about these languages:
+- Javascript tutorial: https://javascript.info/
+ - We particularly recommend you to read about [Promises](https://es.javascript.info/promise-basics)
+
+You can also learn by doing, following this guide and encouraging you to try making changes or adding new screens.
+
+## Architectural Design
+
+
+The LimeApp is a web application built on top of the [Preact framework](https://preactjs.com/) which is very similar to React, yet we chose it because it takes less space (3kB).
+The application bundle, which includes all the application code executable by a web browser, is hosted in `/www/app` and is served by the uHTTPd webserver when visiting the IP address of the router or the domain associated with it, typically: thisnode.info.
+
+uHTTPd has a plugin for [ubus](https://openwrt.org/docs/techref/ubus) that allows us to make ubus calls to the different libremesh services/modules through HTTP POST requests using the JSON RPC (Remote Procedure Call) message protocol.
+This is the interface used in the LimeApp to make calls to the `backend` (the router).
+
+It does not matter if you are not familiar with these technologies right now, you will discover them through practice.
+
+## The elements of the LimeApp
+A typical LimeApp functionality implements a screen composed of one or more Preact `Components`.
+The `Components` define what is rendered on screen, specifying the visual aspect of the screen (HTML + css) and the logical one: what is displayed, when, and which action each button performs.
+In the LimeApp screens we commonly want to display information that is available on the router, (e.g. how long ago it was turned on), and perform actions that modify the router configuration (e.g. change the administration password). This is what we mean by `backend` calls.
+To connect the interface with `backend` calls the `Components` use `Queries` and `Mutations` from the [React Query](https://react-query.tanstack.com/) library.
+This library allows us to declaratively indicate what data (`Queries`) each component uses and what actions (`Mutations`) each component performs. And it also relieves us from the complexity of: re-rendering each screen component that depends on a data that was updated in the `backend`, de-duplicating repeated calls, and managing the cache of these calls to avoid asking twice for the same data unnecessarily.
+
+The `Queries` and `Mutations` call asynchronous functions that define the url endpoints and the body of the requests to the backend. We call these functions API endpoints. They match one by one with the `backend` endpoints.
+All of them use a common interface, the `uHTTPd client`, a singleton that abstracts us from handling the ubus session id, the base url address of the webserver and the details of the JSON RPC protocol.
+
+## Example
+
+To better understand how all these pieces interact with each other, let's see an example:
+Remote Access. Remote Access allows you to open a terminal session on the router to be accessed remotely by another person to help diagnose problems on the network. In the LimeApp we implemented this functionality based on [tmate](tmate.io). The screen allows you to view the current session token, close the current session or open a new session.
+Let's start the tour!
+
+### Tests
+
+The LimeApp has a growing test battery. This battery provides a testing setup and sample tests that allow us to develop new functionality using [Test Driven Development](https://en.wikipedia.org/wiki/Test-driven_development).
+
+To implement the tests we use the Testing Framework [Jest](https://jestjs.io/) together with the [Testing Library](https://testing-library.com/).
+This library allows us to write tests that verify the performance of our components from the user's perspective, and are resistant to implementation changes.
+
+The testing strategy is as follows:
+We test two things separately:
+- 1) the component that renders the functionality we are testing, by mocking the API endpoints that call the `backend`.
+- 2) the API endpoints that call the `backend`.
+This way, if the tests for the API endpoints pass, the endpoint mocks in the component tests match the tested implementation and the component tests also pass, we are guaranteed that the component works as expected, from the interface to the backend calls.
+
+The reason for doing this two-step split is that it fits very well with Jest's mocking capabilities.
+
+#### Component Tests
+The main tip for writing component tests is to think about the requirements it has to fulfill from the user's perspective. They are usually of the type:
+"If I click button A, it shows me text B".
+"If I submit form B, and the backend reports an error, it shows me the error."
+We also test that the endpoints are called with the correct parameters.
+
+In order to mock the API endpoints, we first have to define them. We can postpone the actual implementation for later.
+
+```javascript
+// File at: lime-plugin-remotesupport/src/remoteSupportApi.js
+
+export function getSession() {}
+export function openSession() {}
+export function closeSession() {}
+```
+
+These are the functions that our `Queries` and `Mutations` will use later, for the moment they don't do anything, they only allow us to mock them.
+
+Now we are ready to define the tests of the component. Each part is explained in the comments.
+
+```javascript
+// File at: lime-plugin-remotesupport/remoteSupport.spec.js
+
+// Import utils from the Testing Library
+import { fireEvent, cleanup, act, screen } from '@testing-library/preact';
+import '@testing-library/jest-dom';
+
+// Import the test utility "render" which helps us to render the component in the same context as it will be rendered in the final application.
+import { render } from 'utils/test_utils';
+
+// Import the main component for the remote support screen, which we didn't implement yet.
+import RemoteSupportPage from './src/remoteSupportPage';
+
+// Import and mock the API endpoints that we defined above.
+import { getSession, openSession, closeSession } from './src/remoteSupportApi';
+jest.mock('./src/remoteSupportApi');
+
+describe('Remote Support Page', () => {
+ // Before each test we mock API endpoints with the default mock implementation.
+ beforeEach(() => {
+ getSession.mockImplementation(async () =>
+ ({ rw_ssh: 'ssh -p2222 test_rw_token@test_host', ro_ssh: 'ssh -p2222 test_ro_token@test_host'})
+ );
+ openSession.mockImplementation(async () => null);
+ closeSession.mockImplementation(async () => null);
+ });
+
+ // After each test we cleanup the testing environment.
+ afterEach(() => {
+ cleanup();
+ act(() => queryCache.clear());
+ });
+
+ // We test that the expected elements are rendered in each scenario.
+
+ it('shows a button to create session when there is no session', async () => {
+ getSession.mockImplementation(async () => null);
+ render();
+ expect(await screen.findByRole('button', {name: /create session/i })).toBeEnabled();
+ });
+
+ it('shows rw session token when there is an open session', async () => {
+ render();
+ expect(await screen.findByText('ssh -p2222 test_rw_token@test_host')).toBeInTheDocument();
+ })
+
+ it('shows a button to close session when there is an open session', async () => {
+ render();
+ expect(await screen.findByRole('button', {name: /close session/i})).toBeEnabled();
+ })
+
+ it('show an error when open session fails', async() => {
+ getSession.mockImplementation(async() => null);
+ openSession.mockImplementation(async() => { throw new Error() })
+ render()
+ fireEvent.click(
+ await screen.findByRole('button', {name: /create session/i })
+ );
+ expect(await screen.findByText(/Cannot connect to the remote support server/i)).toBeVisible();
+ });
+});
+```
+
+Once we have the component tests we can get into the component implementation itself (`RemoteSupportPage`).
+
+> Tip: Using `it.skip(...)` we can mark the tests so that they are not executed, and gradually unmark from the simplest to the most complex, as we advance in the implementation.
+
+> Tip: be careful if you are using the `render()` function from `utils/test_utils`, it include the `ReactQueryCacheProvider`, which have to be clear `afterEach` test in order to reset the query cache. See the example above.
+
+To run the tests we do:
+```
+npm run test plugins/lime-plugin-remotesupport/remoteSupport.spec.js
+```
+
+
+#### API endpoints tests
+After having created the tests of the component, surely we already have more confidence in what data and what actions each one of the API endpoints should perform. We can discuss the API with whoever developed the `backend` and settle it down on the tests.
+
+```javascript
+// File Path: lime-plugin-remotesupport/src/remoteSupportApi.spec.js
+
+// Import and mock the uHTTPd client
+import api from 'utils/uhttpd.service';
+jest.mock('utils/uhttpd.service')
+
+// Import the API endpoints to be tested
+import { getSession, openSession, closeSession } from './remoteSupportApi';
+
+// Before each test we reset the uHTTPd client mock implementation.
+beforeEach(() => {
+ api.call.mockClear();
+ api.call.mockImplementation(async () => ({ status: 'ok' }));
+})
+
+describe('getSession', () => {
+ it('calls the expected endpoint', async () => {
+ await getSession();
+ expect(api.call).toBeCalledWith('tmate', 'get_session', {});
+ })
+
+ it('resolves to session when there is a connected session', async () => {
+ const sessionData = {
+ rw_ssh: 'ssh -p2222 pL2qpxKQvPP9f9GPWjG2WkfrM@ny1.tmate.io',
+ ro_ssh: 'ssh -p2222 pL2qpxKQvPP9f9GPWjG2WkfrM@ny1.tmate.io'
+ };
+ api.call.mockImplementation(async () => (
+ {
+ status: 'ok',
+ session: sessionData,
+ }));
+ let session = await getSession();
+ expect(session).toEqual(sessionData);
+ });
+
+ it('resolves to null when there is a non established session', async () => {
+ const sessionData = {
+ rw_ssh: "", ro_ssh: ""
+ };
+ api.call.mockImplementation(async () => (
+ {
+ status: 'ok',
+ session: sessionData,
+ }));
+ let session = await getSession();
+ expect(session).toBeNull();
+ });
+});
+
+describe('closeSession', () => {
+ it('calls the expected endpoint', async () => {
+ await closeSession();
+ expect(api.call).toBeCalledWith('tmate', 'close_session', {})
+ })
+});
+
+describe('openSession', () => {
+ it('calls the expected endpoint', async () => {
+ await openSession();
+ expect(api.call).toBeCalledWith('tmate', 'open_session', {})
+ })
+
+ it('resolves to api response on success', async () => {
+ const result = await openSession();
+ expect(result).toEqual({ status: 'ok'})
+ })
+
+ it('rejects to api call error on error', async () => {
+ api.call.mockImplementationOnce(() => Promise.reject('timeout'));
+ api.call.mockImplementationOnce(async () => ({'status': 'ok'}));
+ expect.assertions(1);
+ try {
+ await openSession()
+ } catch (e) {
+ expect(e).toEqual('timeout')
+ }
+ })
+
+ it('calls close session when rejected ', async () => {
+ api.call.mockImplementationOnce(() => Promise.reject('timeout'));
+ api.call.mockImplementationOnce(async () => ({'status': 'ok'}));
+ expect.assertions(1);
+ try {
+ await openSession()
+ } catch (e) {
+ expect(api.call).toBeCalledWith('tmate', 'close_session', {})
+ }
+ })
+});
+
+```
+
+Once we have written the tests for our API endpoints we can implement them.
+
+### Queries and Mutations
+
+The Queries and Mutations will connect our component with the API endpoints.
+They relieve us from the complexity of re-rendering each component on the screen that depends on data that was updated in the `backend`. That is, if there is more than one component on the screen that depends on the same `Query` and one of the two performs an action that updates the `backend` data, both components will be re-rendered to show the updated information.
+They also allow us to de-duplicate repeated calls, and manage the cache of these calls, so we can use the same `Query` in many components without that meaning multiple and unnecessary repeated requests to the `backend`. All that is articulated in a global instance of the `QueryCache`.
+The `Queries` and `Mutations` are (Hooks)[https://preactjs.com/guide/v10/hooks/] of Preact.
+
+Without further delay, let's implement them, each part is explained in the comments.
+
+```javascript
+// Path: lime-plugin-remotesupport/src/remoteSupportQueries.js
+
+// Import react-query hooks
+import { useQuery, useMutation } from '@tanstack/react-query';
+// Import the singleton instance of QueryCache.
+import queryCache from 'utils/queryCache';
+import { getSession, openSession, closeSession } from './remoteSupportApi'
+
+export function useSession() {
+ // Each Query has a unique identifier in the QueryCache. In this case: ["tmate", "get_session"]
+ // The second parameter is an asynchronous function, the API endpoint.
+ return useQuery(["tmate", "get_session"], getSession);
+}
+
+export function useOpenSession() {
+ return useMutation(openSession, {
+ // After successfully opening a new session, we invalidate the useSession query.
+ // This will force all rendered components using the session information to be re-rendered to show up the new session data.
+ onSuccess: () => queryCache.invalidateQueries(["tmate", "get_session"]),
+ // We can also set specific data for a query in the queryCache.
+ // In this case, in which openSession failed, we specify null as the new session data.
+ onError: () => queryCache.setQueryData(["tmate", "get_session"], null)
+ })
+}
+
+export function useCloseSession() {
+ return useMutation(closeSession, {
+ onSuccess: () => queryCache.invalidateQueries(["tmate", "get_session"])
+ })
+}
+```
+
+Now that we have our `Queries` and `Mutations` written, we can use them in the `Component`.
+
+### Component
+
+The main `Component` has to render the Remote Access screen. It has to comply with the tests that we defined in section "4.1.2 Component Tests".
+A strategy that works well in practice is to iterate the implementation so that it satisfies the simplest tests first, and then the more complex ones. That way we keep the room for introducing bugs tight, and debugging becomes easier.
+To define what is rendered, we use [JSX](https://reactjs.org/docs/introducing-jsx.html), an extension to JavaScript which allows us to define the structure of the document in a declarative way, and then Babel compiles it to DOM imperative calls of type document.createElement().
+Let's see how our component that passes the tests is implemented.
+
+```javascript
+// File Path: lime-plugin-remotesupport/src/remoteSupportPage.js
+import { useSession, useOpenSession, useCloseSession } from './remoteSupportQueries';
+import Loading from 'components/loading';
+// We use lingui for internazionalization
+import { Trans } from '@lingui/macro';
+
+const RemoteSupportPage = () => {
+ // React Query make it easy to see the status of a query (i.e, isLoading).
+ const {data: session, isLoading: loadingSession} = useSession();
+ const [openSession, openStatus] = useOpenSession();
+ const [closeSession, closeStatus] = useCloseSession();
+
+ if (loadingSession) {
+ return
+ }
+
+ return(
+
+
Ask for remote support
+ {!session &&
+
+
There's no open session for remote support. Click at Create Session to begin one
+
+
+ }
+ {openStatus.isError &&
+
+ Cannot connect to the remote support server
+ Please verify your internet connection
+
+ }
+ {session &&
+
+
There's an active remote support session
+
Share the following command with whoever you want to give them access to your node
+
{session.rw_ssh}
+
+
Close Session
+
Click at Close Session to end the remote support session. No one will be able to access your node with this token again