diff --git a/.editorconfig b/.editorconfig
index b585a761..4e5c9337 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -11,3 +11,7 @@ trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
+
+[*.yaml]
+indent_size = 2
+
diff --git a/.eslintrc.json b/.eslintrc.json
index 4151e9e9..ac803e7b 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,61 +1,46 @@
{
- "root": true,
- "ignorePatterns": [
- "projects/**/*"
- ],
- "overrides": [
- {
- "files": [
- "*.ts"
- ],
- "parserOptions": {
- "project": [
- "tsconfig.json",
- "e2e/tsconfig.json"
- ],
- "createDefaultProgram": true
- },
- "extends": [
- "plugin:@angular-eslint/recommended",
- "plugin:@angular-eslint/template/process-inline-templates"
- ],
- "rules": {
- "@angular-eslint/component-selector": [
- "error",
- {
- "prefix": "app",
- "style": "kebab-case",
- "type": "element"
- }
- ],
- "@angular-eslint/directive-selector": [
- "error",
- {
- "prefix": "app",
- "style": "camelCase",
- "type": "attribute"
- }
- ],
- "@angular-eslint/component-class-suffix": [
- "error",
- {
- "suffixes": [
- "Page",
- "Component",
- "Dialog"
- ]
- }
- ]
- }
- },
- {
- "files": [
- "*.html"
- ],
- "extends": [
- "plugin:@angular-eslint/template/recommended"
- ],
- "rules": { }
- }
- ]
+ "root": true,
+ "ignorePatterns": ["projects/**/*"],
+ "overrides": [
+ {
+ "files": ["*.ts"],
+ "parserOptions": {
+ "project": ["tsconfig.json", "e2e/tsconfig.json"],
+ "createDefaultProgram": true
+ },
+ "extends": [
+ "plugin:@angular-eslint/recommended",
+ "plugin:@angular-eslint/template/process-inline-templates"
+ ],
+ "rules": {
+ "@angular-eslint/component-selector": [
+ "error",
+ {
+ "prefix": "app",
+ "style": "kebab-case",
+ "type": "element"
+ }
+ ],
+ "@angular-eslint/directive-selector": [
+ "error",
+ {
+ "prefix": "app",
+ "style": "camelCase",
+ "type": "attribute"
+ }
+ ],
+ "@angular-eslint/component-class-suffix": [
+ "error",
+ {
+ "suffixes": ["Page", "Component", "Dialog"]
+ }
+ ]
+ }
+ },
+ {
+ "files": ["*.html"],
+ "extends": ["plugin:@angular-eslint/template/recommended"],
+ "rules": {}
+ }
+ ]
}
diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml
index 5a51f7a6..7bfc08fe 100644
--- a/.github/workflows/docker.yaml
+++ b/.github/workflows/docker.yaml
@@ -53,7 +53,7 @@ jobs:
- name: Clean up old images
uses: actions/delete-package-versions@v5
with:
- package-name: 'leaphy-webbased/leaphy-webbased'
- package-type: 'container'
+ package-name: "leaphy-webbased/leaphy-webbased"
+ package-type: "container"
min-versions-to-keep: 5
- delete-only-untagged-versions: 'true'
+ delete-only-untagged-versions: "true"
diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml
index 780c68c0..48c8ec87 100644
--- a/.github/workflows/playwright.yml
+++ b/.github/workflows/playwright.yml
@@ -1,29 +1,33 @@
name: Playwright Tests
on:
- pull_request:
- branches: [ main, master ]
+ pull_request:
+ branches: [main, master]
jobs:
- test:
- timeout-minutes: 60
- runs-on: ubuntu-latest
- container:
- image: mcr.microsoft.com/playwright:v1.42.1-jammy
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- with:
- node-version: '20.x'
- registry-url: 'https://registry.npmjs.org'
- cache: yarn
- - name: Install node modules
- run: yarn --frozen-lockfile --prefer-offline
- - name: Run linter
- run: yarn lint
- - name: Run Playwright tests
- run: yarn playwright test
- - uses: actions/upload-artifact@v4
- if: always()
- with:
- name: playwright-report
- path: playwright-report/
- retention-days: 30
+ test:
+ timeout-minutes: 60
+ runs-on: ubuntu-latest
+ container:
+ image: mcr.microsoft.com/playwright:v1.42.1-jammy
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: "20.x"
+ registry-url: "https://registry.npmjs.org"
+ cache: yarn
+ - name: Install node modules
+ run: yarn --frozen-lockfile --prefer-offline
+ - name: Run linter
+ run: yarn lint
+ - name: Run ESLint
+ run: npx eslint .
+ - name: Run prettier
+ run: npx prettier -c ./src
+ - name: Run Playwright tests
+ run: yarn playwright test
+ - uses: actions/upload-artifact@v4
+ if: always()
+ with:
+ name: playwright-report
+ path: playwright-report/
+ retention-days: 30
diff --git a/README.md b/README.md
index c7a6c38d..ac798fe9 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,26 @@
# Leaphy Easybloqs
## Introduction
+
Leaphy Easybloqs is software to program [Leaphy Robots](https://www.leaphy.nl) and Arduino microcontrollers using a block-based programming language and a user-friendly interface.
It also support programming RP2040 controllers that are able to run MicroPython.
## Contributing
-We welcome PRs from anyone that wants to contribute!
+
+We welcome PRs from anyone that wants to contribute!
### Prerequisites
The following should be installed:
-- NodeJS (Version 20.X)
+- NodeJS (Version 20.X)
On Windows: Be sure to install the build tools by checking the box during the NodeJS installation process
-- Yarn v1
+- Yarn v1
### Running locally
-First install the dependencies by running `yarn intall`. This will take a while the first time.
-Then run `yarn start` to start the application.
-
+First install the dependencies by running `yarn intall`. This will take a while the first time.
+Then run `yarn start` to start the application.
### Pull Requests
@@ -30,4 +31,3 @@ Once merged, it will show up on https://testleaphyeasybloqs.com for integration
All issues that involve webbased should be reported on the [Leaphy Easybloqs Webbased GitHub](https://github.com/leaphy-robotics/leaphy-webbased/issues) page.
Issues that involve the blocks should be reported on the [Leaphy Blocks GitHub](https://github.com/leaphy-robotics/leaphy-blocks/issues) page.
-
diff --git a/angular.json b/angular.json
index e1390572..046c1768 100644
--- a/angular.json
+++ b/angular.json
@@ -143,7 +143,7 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
- "headers": {
+ "headers": {
"Cross-Origin-Embedder-Policy": "require-corp",
"Cross-Origin-Opener-Policy": "same-origin"
},
@@ -151,17 +151,17 @@
},
"configurations": {
"production": {
- "buildTarget": "leaphy-client:build:production"
+ "buildTarget": "leaphy-client:build:production"
},
"dev": {
- "buildTarget": "leaphy-client:build:dev"
+ "buildTarget": "leaphy-client:build:dev"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
- "buildTarget": "leaphy-client:build"
+ "buildTarget": "leaphy-client:build"
}
},
"test": {
@@ -170,10 +170,7 @@
"main": "src/test.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
- "assets": [
- "src/favicon.ico",
- "src/assets"
- ],
+ "assets": ["src/favicon.ico", "src/assets"],
"styles": [
"src/styles.scss",
"src/theme.scss",
@@ -185,10 +182,7 @@
"lint": {
"builder": "@angular-eslint/builder:lint",
"options": {
- "lintFilePatterns": [
- "src/**/*.ts",
- "src/**/*.html"
- ]
+ "lintFilePatterns": ["src/**/*.ts", "src/**/*.html"]
}
},
"e2e": {
@@ -210,9 +204,7 @@
}
},
"cli": {
- "analytics": "6d8c3839-2848-4328-b7fb-a10f9273fdfc",
- "schematicCollections": [
- "@angular-eslint/schematics"
- ]
+ "analytics": "6d8c3839-2848-4328-b7fb-a10f9273fdfc",
+ "schematicCollections": ["@angular-eslint/schematics"]
}
}
diff --git a/package.json b/package.json
index 83549be8..ddf24c0e 100644
--- a/package.json
+++ b/package.json
@@ -1,103 +1,104 @@
{
- "name": "leaphy_webbased",
- "productName": "Leaphy Webbased",
- "author": "Leaphy Robotics",
- "description": "Build Leaphy Arduino programs",
- "version": "3.0.0",
- "license": "GPLv3",
- "main": "src/main.ts",
- "scripts": {
- "ng": "ng",
- "start": "ng serve --open --configuration dev",
- "build": "ng build --configuration production --base-href ./",
- "buildLocal": "ng build --configuration local --base-href ./",
- "buildstart": "ng build --base-href ./ && yarn run start",
- "test": "ng test",
- "lint": "ng lint",
- "e2e": "ng e2e",
- "dev": "lite-server --baseDir=\"dist\""
- },
- "private": true,
- "dependencies": {
- "@angular/animations": "17.3.4",
- "@angular/cdk": "^17.3.4",
- "@angular/common": "~17.3.4",
- "@angular/compiler": "~17.3.4",
- "@angular/core": "~17.3.4",
- "@angular/flex-layout": "^15.0.0-beta.42",
- "@angular/forms": "~17.3.4",
- "@angular/material": "^17.3.4",
- "@angular/platform-browser": "~17.3.4",
- "@angular/platform-browser-dynamic": "~17.3.4",
- "@angular/router": "17.3.4",
- "@blockly/field-bitmap": "^4.0.13",
- "@blockly/workspace-backpack": "^5.3.3",
- "@fortawesome/fontawesome-free": "^6.1.1",
- "@leaphy-robotics/avrdude-webassembly": "^1.4.0",
- "@leaphy-robotics/dfu-util-wasm": "1.0.2",
- "@leaphy-robotics/leaphy-blocks": "2.0.2",
- "@leaphy-robotics/picotool-wasm": "1.0.2",
- "@ngx-translate/core": "^14.0.0",
- "@ngx-translate/http-loader": "^7.0.0",
- "@serialport/parser-readline": "^10.3.0",
- "@types/w3c-web-serial": "^1.0.3",
- "base64-js": "^1.5.1",
- "blockly": "^10.1.3",
- "bootstrap": "^5.1.3",
- "buffer": "^6.0.3",
- "chart.js": "^3.8.0",
- "chartjs-adapter-moment": "^1.0.0",
- "jquery": "^3.5.1",
- "jszip": "^3.10.1",
- "moment": "^2.30.1",
- "monaco-editor": "^0.47.0",
- "ng-terminal": "~6.1.0",
- "ng2-charts": "3.0.11",
- "ngx-matomo-client": "^6.1.3",
- "ngx-monaco-editor-v2": "^17.0.1",
- "papaparse": "^5.4.1",
- "rxjs": "~7.5.5",
- "showdown": "^2.1.0",
- "tslib": "^2.4.0",
- "web-serial-polyfill": "^1.0.15",
- "zone.js": "~0.14.3"
- },
- "devDependencies": {
- "@angular-devkit/build-angular": "^17.3.4",
- "@angular-eslint/builder": "17.3.0",
- "@angular-eslint/eslint-plugin": "17.3.0",
- "@angular-eslint/eslint-plugin-template": "17.3.0",
- "@angular-eslint/schematics": "17.3.0",
- "@angular-eslint/template-parser": "17.3.0",
- "@angular/cli": "^17.3.4",
- "@angular/compiler-cli": "~17.3.4",
- "@angular/language-service": "~17.3.4",
- "@playwright/test": "^1.42.1",
- "@types/jasmine": "~4.0.3",
- "@types/jasminewd2": "~2.0.3",
- "@types/node": "^20.4.8",
- "@types/w3c-web-usb": "^1.0.10",
- "@typescript-eslint/eslint-plugin": "^7.2.0",
- "@typescript-eslint/parser": "^7.2.0",
- "eslint": "^8.57.0",
- "jasmine-core": "~4.1.1",
- "jasmine-spec-reporter": "~7.0.0",
- "karma": "~6.3.20",
- "karma-chrome-launcher": "~3.1.1",
- "karma-coverage-istanbul-reporter": "~3.0.2",
- "karma-jasmine": "~5.0.1",
- "karma-jasmine-html-reporter": "^2.0.0",
- "protractor": "~7.0.0",
- "ts-node": "~10.8.0",
- "typescript": "5.4.5"
- },
- "config": {
- "forge": "./forge.config.js"
- },
- "browser": {
- "crypto": false,
- "constants": false,
- "fs": false,
- "path": false
- }
+ "name": "leaphy_webbased",
+ "productName": "Leaphy Webbased",
+ "author": "Leaphy Robotics",
+ "description": "Build Leaphy Arduino programs",
+ "version": "3.0.0",
+ "license": "GPLv3",
+ "main": "src/main.ts",
+ "scripts": {
+ "ng": "ng",
+ "start": "ng serve --open --configuration dev",
+ "build": "ng build --configuration production --base-href ./",
+ "buildLocal": "ng build --configuration local --base-href ./",
+ "buildstart": "ng build --base-href ./ && yarn run start",
+ "test": "ng test",
+ "lint": "ng lint",
+ "e2e": "ng e2e",
+ "dev": "lite-server --baseDir=\"dist\""
+ },
+ "private": true,
+ "dependencies": {
+ "@angular/animations": "17.3.4",
+ "@angular/cdk": "^17.3.4",
+ "@angular/common": "~17.3.4",
+ "@angular/compiler": "~17.3.4",
+ "@angular/core": "~17.3.4",
+ "@angular/flex-layout": "^15.0.0-beta.42",
+ "@angular/forms": "~17.3.4",
+ "@angular/material": "^17.3.4",
+ "@angular/platform-browser": "~17.3.4",
+ "@angular/platform-browser-dynamic": "~17.3.4",
+ "@angular/router": "17.3.4",
+ "@blockly/field-bitmap": "^4.0.13",
+ "@blockly/workspace-backpack": "^5.3.3",
+ "@fortawesome/fontawesome-free": "^6.1.1",
+ "@leaphy-robotics/avrdude-webassembly": "^1.4.0",
+ "@leaphy-robotics/dfu-util-wasm": "1.0.2",
+ "@leaphy-robotics/leaphy-blocks": "2.0.2",
+ "@leaphy-robotics/picotool-wasm": "1.0.2",
+ "@ngx-translate/core": "^14.0.0",
+ "@ngx-translate/http-loader": "^7.0.0",
+ "@serialport/parser-readline": "^10.3.0",
+ "@types/w3c-web-serial": "^1.0.3",
+ "base64-js": "^1.5.1",
+ "blockly": "^10.1.3",
+ "bootstrap": "^5.1.3",
+ "buffer": "^6.0.3",
+ "chart.js": "^3.8.0",
+ "chartjs-adapter-moment": "^1.0.0",
+ "jquery": "^3.5.1",
+ "jszip": "^3.10.1",
+ "moment": "^2.30.1",
+ "monaco-editor": "^0.47.0",
+ "ng-terminal": "~6.1.0",
+ "ng2-charts": "3.0.11",
+ "ngx-matomo-client": "^6.1.3",
+ "ngx-monaco-editor-v2": "^17.0.1",
+ "papaparse": "^5.4.1",
+ "rxjs": "~7.5.5",
+ "showdown": "^2.1.0",
+ "tslib": "^2.4.0",
+ "web-serial-polyfill": "^1.0.15",
+ "zone.js": "~0.14.3"
+ },
+ "devDependencies": {
+ "@angular-devkit/build-angular": "^17.3.4",
+ "@angular-eslint/builder": "17.3.0",
+ "@angular-eslint/eslint-plugin": "17.3.0",
+ "@angular-eslint/eslint-plugin-template": "17.3.0",
+ "@angular-eslint/schematics": "17.3.0",
+ "@angular-eslint/template-parser": "17.3.0",
+ "@angular/cli": "^17.3.4",
+ "@angular/compiler-cli": "~17.3.4",
+ "@angular/language-service": "~17.3.4",
+ "@playwright/test": "^1.42.1",
+ "@types/jasmine": "~4.0.3",
+ "@types/jasminewd2": "~2.0.3",
+ "@types/node": "^20.4.8",
+ "@types/w3c-web-usb": "^1.0.10",
+ "@typescript-eslint/eslint-plugin": "^7.2.0",
+ "@typescript-eslint/parser": "^7.2.0",
+ "eslint": "^8.57.0",
+ "jasmine-core": "~4.1.1",
+ "jasmine-spec-reporter": "~7.0.0",
+ "karma": "~6.3.20",
+ "karma-chrome-launcher": "~3.1.1",
+ "karma-coverage-istanbul-reporter": "~3.0.2",
+ "karma-jasmine": "~5.0.1",
+ "karma-jasmine-html-reporter": "^2.0.0",
+ "prettier": "^3.2.5",
+ "protractor": "~7.0.0",
+ "ts-node": "~10.8.0",
+ "typescript": "5.4.5"
+ },
+ "config": {
+ "forge": "./forge.config.js"
+ },
+ "browser": {
+ "crypto": false,
+ "constants": false,
+ "fs": false,
+ "path": false
+ }
}
diff --git a/playwright.config.ts b/playwright.config.ts
index 4ee1c22c..64fc0dcb 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -1,4 +1,4 @@
-import { defineConfig, devices } from '@playwright/test';
+import { defineConfig, devices } from "@playwright/test";
/**
* Read environment variables from file.
@@ -10,58 +10,58 @@ import { defineConfig, devices } from '@playwright/test';
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
- testDir: './tests',
- /* Run tests in files in parallel */
- fullyParallel: true,
- /* Fail the build on CI if you accidentally left test.only in the source code. */
- forbidOnly: !!process.env.CI,
- /* Retry on CI only */
- retries: process.env.CI ? 2 : 0,
- /* Opt out of parallel tests on CI. */
- workers: process.env.CI ? 1 : undefined,
- /* Reporter to use. See https://playwright.dev/docs/test-reporters */
- reporter: 'html',
- /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
- use: {
- /* Base URL to use in actions like `await page.goto('/')`. */
- baseURL: 'http://localhost:4200/',
+ testDir: "./tests",
+ /* Run tests in files in parallel */
+ fullyParallel: true,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: "html",
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
+ /* Base URL to use in actions like `await page.goto('/')`. */
+ baseURL: "http://localhost:4200/",
- /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
- trace: 'on-first-retry',
- },
-
- /* Configure projects for major browsers */
- projects: [
- {
- name: 'chromium',
- use: { ...devices['Desktop Chrome'] },
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: "on-first-retry",
},
- /* These browers are not supported because of their lack of webserial support, so we don't need to test them */
- // {
- // name: 'firefox',
- // use: { ...devices['Desktop Firefox'] },
- // },
- // {
- // name: 'webkit',
- // use: { ...devices['Desktop Safari'] },
- // },
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: "chromium",
+ use: { ...devices["Desktop Chrome"] },
+ },
+
+ /* These browers are not supported because of their lack of webserial support, so we don't need to test them */
+ // {
+ // name: 'firefox',
+ // use: { ...devices['Desktop Firefox'] },
+ // },
+ // {
+ // name: 'webkit',
+ // use: { ...devices['Desktop Safari'] },
+ // },
- /* Test against branded browsers. */
- // {
- // name: 'Microsoft Edge',
- // use: { ...devices['Desktop Edge'], channel: 'msedge' },
- // },
- // {
- // name: 'Google Chrome',
- // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
- // },
- ],
+ /* Test against branded browsers. */
+ // {
+ // name: 'Microsoft Edge',
+ // use: { ...devices['Desktop Edge'], channel: 'msedge' },
+ // },
+ // {
+ // name: 'Google Chrome',
+ // use: { ...devices['Desktop Chrome'], channel: 'chrome' },
+ // },
+ ],
- /* Run your local dev server before starting the tests */
- webServer: {
- command: 'yarn start',
- url: 'http://localhost:4200/',
- reuseExistingServer: !process.env.CI,
- },
+ /* Run your local dev server before starting the tests */
+ webServer: {
+ command: "yarn start",
+ url: "http://localhost:4200/",
+ reuseExistingServer: !process.env.CI,
+ },
});
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 72153a0e..ac362e06 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -1,38 +1,62 @@
-import { NgModule } from '@angular/core';
-import { Routes, RouterModule } from '@angular/router';
-import {CodeEditorPythonPage} from "./modules/code-editor-python/code-editor-python.page";
-import {DriverIssuesEnglishPage} from "./modules/driver-issues-english/driver-issues.page";
-import {DriverIssuesDutchPage} from "./modules/driver-issues-dutch/driver-issues.page";
-import {BlocklyEditorPage} from "./modules/blockly-editor/blockly-editor.page";
-import {CodeEditorCppPage} from "./modules/code-editor-cpp/code-editor-cpp.page";
-import {MonacoEditorModule} from "ngx-monaco-editor-v2";
-
+import { NgModule } from "@angular/core";
+import { Routes, RouterModule } from "@angular/router";
+import { CodeEditorPythonPage } from "./modules/code-editor-python/code-editor-python.page";
+import { DriverIssuesEnglishPage } from "./modules/driver-issues-english/driver-issues.page";
+import { DriverIssuesDutchPage } from "./modules/driver-issues-dutch/driver-issues.page";
+import { BlocklyEditorPage } from "./modules/blockly-editor/blockly-editor.page";
+import { CodeEditorCppPage } from "./modules/code-editor-cpp/code-editor-cpp.page";
+import { MonacoEditorModule } from "ngx-monaco-editor-v2";
const routes: Routes = [
- { path: 'blocks', children: [{
- path: '',
- component: BlocklyEditorPage
- }]},
- { path: 'cppEditor', children: [{
- path: '',
- component: CodeEditorCppPage
- }]},
- { path: 'pythonEditor', children: [{
- path: '',
- component: CodeEditorPythonPage
- }]},
- { path: 'en', children: [{
- path: 'driverissues',
- component: DriverIssuesEnglishPage
- }]},
- { path: 'nl', children: [{
- path: 'driverissues',
- component: DriverIssuesDutchPage
- }]}
+ {
+ path: "blocks",
+ children: [
+ {
+ path: "",
+ component: BlocklyEditorPage,
+ },
+ ],
+ },
+ {
+ path: "cppEditor",
+ children: [
+ {
+ path: "",
+ component: CodeEditorCppPage,
+ },
+ ],
+ },
+ {
+ path: "pythonEditor",
+ children: [
+ {
+ path: "",
+ component: CodeEditorPythonPage,
+ },
+ ],
+ },
+ {
+ path: "en",
+ children: [
+ {
+ path: "driverissues",
+ component: DriverIssuesEnglishPage,
+ },
+ ],
+ },
+ {
+ path: "nl",
+ children: [
+ {
+ path: "driverissues",
+ component: DriverIssuesDutchPage,
+ },
+ ],
+ },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
- exports: [RouterModule]
+ exports: [RouterModule],
})
-export class AppRoutingModule { }
+export class AppRoutingModule {}
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 4af68343..3cb52de5 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,6 +1,6 @@
@if (appState.selectedRobotType$ | async) {
-
+
} @else {
-
+
}
diff --git a/src/app/app.component.scss b/src/app/app.component.scss
index 7d570afb..1d5cca77 100644
--- a/src/app/app.component.scss
+++ b/src/app/app.component.scss
@@ -1,13 +1,13 @@
.imgcenter {
- position:absolute;
- top: 50%;
- left:50%;
- -webkit-transform: translate(-50%, -50%);
- -ms-transform: translate(-50%, -50%);
- transform: translate(-50%, -50%);
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ transform: translate(-50%, -50%);
}
.main_logo {
- width: 0.001%;
- height:auto;
+ width: 0.001%;
+ height: auto;
}
diff --git a/src/app/app.component.spec.ts b/src/app/app.component.spec.ts
index dc2ea919..c6e9c4f9 100644
--- a/src/app/app.component.spec.ts
+++ b/src/app/app.component.spec.ts
@@ -1,35 +1,33 @@
-import { TestBed, waitForAsync } from '@angular/core/testing';
-import { RouterTestingModule } from '@angular/router/testing';
-import { AppComponent } from './app.component';
+import { TestBed, waitForAsync } from "@angular/core/testing";
+import { RouterTestingModule } from "@angular/router/testing";
+import { AppComponent } from "./app.component";
-describe('AppComponent', () => {
- beforeEach(waitForAsync(() => {
- TestBed.configureTestingModule({
- imports: [
- RouterTestingModule
- ],
- declarations: [
- AppComponent
- ],
- }).compileComponents();
- }));
+describe("AppComponent", () => {
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ imports: [RouterTestingModule],
+ declarations: [AppComponent],
+ }).compileComponents();
+ }));
- it('should create the app', () => {
- const fixture = TestBed.createComponent(AppComponent);
- const app = fixture.debugElement.componentInstance;
- expect(app).toBeTruthy();
- });
+ it("should create the app", () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app).toBeTruthy();
+ });
- it(`should have as title 'leaphy-client'`, () => {
- const fixture = TestBed.createComponent(AppComponent);
- const app = fixture.debugElement.componentInstance;
- expect(app.title).toEqual('leaphy-client');
- });
+ it(`should have as title 'leaphy-client'`, () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ const app = fixture.debugElement.componentInstance;
+ expect(app.title).toEqual("leaphy-client");
+ });
- it('should render title', () => {
- const fixture = TestBed.createComponent(AppComponent);
- fixture.detectChanges();
- const compiled = fixture.debugElement.nativeElement;
- expect(compiled.querySelector('.content span').textContent).toContain('leaphy-client app is running!');
- });
+ it("should render title", () => {
+ const fixture = TestBed.createComponent(AppComponent);
+ fixture.detectChanges();
+ const compiled = fixture.debugElement.nativeElement;
+ expect(compiled.querySelector(".content span").textContent).toContain(
+ "leaphy-client app is running!",
+ );
+ });
});
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index e3335766..f01bc4ce 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,23 +1,25 @@
-import { Component } from '@angular/core';
-import { AppState } from './state/app.state';
+import { Component } from "@angular/core";
+import { AppState } from "./state/app.state";
import { MatIconRegistry } from "@angular/material/icon";
import { DomSanitizer } from "@angular/platform-browser";
@Component({
- selector: 'app-root',
- templateUrl: './app.component.html',
- styleUrls: ['./app.component.scss']
+ selector: "app-root",
+ templateUrl: "./app.component.html",
+ styleUrls: ["./app.component.scss"],
})
export class AppComponent {
- title = 'Leaphy Easybloqs';
+ title = "Leaphy Easybloqs";
constructor(
public appState: AppState,
private matIconRegistry: MatIconRegistry,
- private domSanitizer: DomSanitizer
+ private domSanitizer: DomSanitizer,
) {
this.matIconRegistry.addSvgIcon(
"block",
- this.domSanitizer.bypassSecurityTrustResourceUrl("./assets/block.svg")
+ this.domSanitizer.bypassSecurityTrustResourceUrl(
+ "./assets/block.svg",
+ ),
);
}
}
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 68d47432..917eff3b 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -1,35 +1,31 @@
-import { BrowserModule } from '@angular/platform-browser';
-import { NgModule, APP_INITIALIZER } from '@angular/core';
+import { BrowserModule } from "@angular/platform-browser";
+import { NgModule, APP_INITIALIZER } from "@angular/core";
-import { HttpClientModule, HttpClient } from '@angular/common/http';
+import { HttpClientModule, HttpClient } from "@angular/common/http";
-import { AppRoutingModule } from './app-routing.module';
-import { AppComponent } from './app.component';
-import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { AppRoutingModule } from "./app-routing.module";
+import { AppComponent } from "./app.component";
+import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
-import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
-import { TranslateHttpLoader } from '@ngx-translate/http-loader';
+import { TranslateModule, TranslateLoader } from "@ngx-translate/core";
+import { TranslateHttpLoader } from "@ngx-translate/http-loader";
-import { BlocklyEditorEffects } from './effects/blockly-editor.effects';
-import { DialogEffects } from './effects/dialog.effects';
-import { AppEffects } from './effects/app.effects';
-import { RobotWiredEffects } from './effects/robot.wired.effects';
-import { CoreModule } from './modules/core/core.module';
+import { BlocklyEditorEffects } from "./effects/blockly-editor.effects";
+import { DialogEffects } from "./effects/dialog.effects";
+import { AppEffects } from "./effects/app.effects";
+import { RobotWiredEffects } from "./effects/robot.wired.effects";
+import { CoreModule } from "./modules/core/core.module";
-import { MatomoModule } from 'ngx-matomo-client';
-import {CodeEditorEffects} from "./effects/code-editor.effects";
-import {MonacoEditorModule} from "ngx-monaco-editor-v2";
+import { MatomoModule } from "ngx-matomo-client";
+import { CodeEditorEffects } from "./effects/code-editor.effects";
+import { MonacoEditorModule } from "ngx-monaco-editor-v2";
export function createTranslateLoader(http: HttpClient) {
- return new TranslateHttpLoader(http, './assets/i18n/', '.json');
+ return new TranslateHttpLoader(http, "./assets/i18n/", ".json");
}
-
-
@NgModule({
- declarations: [
- AppComponent,
- ],
+ declarations: [AppComponent],
imports: [
BrowserModule,
AppRoutingModule,
@@ -39,35 +35,37 @@ export function createTranslateLoader(http: HttpClient) {
loader: {
provide: TranslateLoader,
useFactory: createTranslateLoader,
- deps: [HttpClient]
- }
+ deps: [HttpClient],
+ },
}),
MatomoModule.forRoot({
- scriptUrl: 'https://leaphyeasybloqs.com/matomo/matomo.js',
+ scriptUrl: "https://leaphyeasybloqs.com/matomo/matomo.js",
trackers: [
{
- trackerUrl: 'https://leaphyeasybloqs.com/matomo/matomo.php',
- siteId: 1
- }
+ trackerUrl: "https://leaphyeasybloqs.com/matomo/matomo.php",
+ siteId: 1,
+ },
],
}),
CoreModule,
- MonacoEditorModule.forRoot()
+ MonacoEditorModule.forRoot(),
],
providers: [
// Initialize the Effects on startup
{
- provide: APP_INITIALIZER, deps:
- [
- AppEffects,
- BlocklyEditorEffects,
- DialogEffects,
- CodeEditorEffects,
- RobotWiredEffects
- ], useFactory: () => () => null, multi: true
- }
+ provide: APP_INITIALIZER,
+ deps: [
+ AppEffects,
+ BlocklyEditorEffects,
+ DialogEffects,
+ CodeEditorEffects,
+ RobotWiredEffects,
+ ],
+ useFactory: () => () => null,
+ multi: true,
+ },
],
exports: [],
- bootstrap: [AppComponent]
+ bootstrap: [AppComponent],
})
-export class AppModule { }
+export class AppModule {}
diff --git a/src/app/domain/language.ts b/src/app/domain/language.ts
index 504b8db1..6fbc5b10 100644
--- a/src/app/domain/language.ts
+++ b/src/app/domain/language.ts
@@ -1,3 +1,6 @@
export class Language {
- constructor(public code: string, public name: string) {}
+ constructor(
+ public code: string,
+ public name: string,
+ ) {}
}
diff --git a/src/app/domain/python-file.type.ts b/src/app/domain/python-file.type.ts
index 8d076705..fc79e31c 100644
--- a/src/app/domain/python-file.type.ts
+++ b/src/app/domain/python-file.type.ts
@@ -1,8 +1,7 @@
export class PythonFile {
- path: string;
+ path: string;
- constructor(path: string) {
- this.path = path;
- }
+ constructor(path: string) {
+ this.path = path;
+ }
}
-
diff --git a/src/app/domain/robot.type.ts b/src/app/domain/robot.type.ts
index b984f2bd..31314b8e 100644
--- a/src/app/domain/robot.type.ts
+++ b/src/app/domain/robot.type.ts
@@ -16,7 +16,7 @@ const DEFAULTS: Features = {
showLeaphyOperators: true,
showLeaphySensors: false,
showLeaphyLists: false,
- showCodeOnStart: false
+ showCodeOnStart: false,
};
interface ProtocolInformation {
@@ -38,22 +38,21 @@ export class RobotType {
public libs: string[],
features?: Partial,
) {
- this.features = Object.assign({}, DEFAULTS, features||{});
+ this.features = Object.assign({}, DEFAULTS, features || {});
}
}
export interface RobotEntry {
- name: string,
- icon: string,
- robot: RobotType
+ name: string;
+ icon: string;
+ robot: RobotType;
}
export interface RobotSelector {
- intercept: RobotType,
- choices: RobotEntry[][],
+ intercept: RobotType;
+ choices: RobotEntry[][];
}
-
export class BaseUno extends RobotType {
constructor(
id: string,
@@ -63,7 +62,17 @@ export class BaseUno extends RobotType {
libs: string[],
features?: Partial,
) {
- super(id, {protocol: Avrdude, microcontroller: 'atmega328p'}, name, svgname, background, "arduino:avr:uno", "arduino:avr", libs, features);
+ super(
+ id,
+ { protocol: Avrdude, microcontroller: "atmega328p" },
+ name,
+ svgname,
+ background,
+ "arduino:avr:uno",
+ "arduino:avr",
+ libs,
+ features,
+ );
}
}
@@ -76,7 +85,17 @@ export class BaseNano extends RobotType {
libs: string[],
features?: Partial,
) {
- super(id, {protocol: Avrdude, microcontroller: 'atmega328p'}, name, svgname, background, "arduino:avr:nano", "arduino:avr", libs, features);
+ super(
+ id,
+ { protocol: Avrdude, microcontroller: "atmega328p" },
+ name,
+ svgname,
+ background,
+ "arduino:avr:nano",
+ "arduino:avr",
+ libs,
+ features,
+ );
}
}
@@ -89,7 +108,17 @@ export class BaseNanoESP32 extends RobotType {
libs: string[],
features?: Partial,
) {
- super(id, {protocol: DFU}, name, svgname, background, "arduino:esp32:nano_nora", "arduino:esp32", libs, features);
+ super(
+ id,
+ { protocol: DFU },
+ name,
+ svgname,
+ background,
+ "arduino:esp32:nano_nora",
+ "arduino:esp32",
+ libs,
+ features,
+ );
}
}
@@ -102,7 +131,16 @@ export class BaseNanoRP2040 extends RobotType {
libs: string[],
features?: Partial,
) {
- super(id, {protocol: Pico}, name, svgname, background, "arduino:mbed_nano:nanorp2040connect", "arduino:mbed_nano", libs, features);
+ super(
+ id,
+ { protocol: Pico },
+ name,
+ svgname,
+ background,
+ "arduino:mbed_nano:nanorp2040connect",
+ "arduino:mbed_nano",
+ libs,
+ features,
+ );
}
}
-
diff --git a/src/app/domain/robots.ts b/src/app/domain/robots.ts
index 76d20730..d438b741 100644
--- a/src/app/domain/robots.ts
+++ b/src/app/domain/robots.ts
@@ -1,17 +1,34 @@
import Avrdude from "../services/arduino-uploader/protocols/avrdude";
-import {BaseNano, BaseNanoESP32, BaseNanoRP2040, BaseUno, RobotType} from "./robot.type";
+import {
+ BaseNano,
+ BaseNanoESP32,
+ BaseNanoRP2040,
+ BaseUno,
+ RobotType,
+} from "./robot.type";
const defaultLibraries = [
- 'Leaphy Original Extension', 'Leaphy Extra Extension', 'Servo', 'Adafruit GFX Library', 'Adafruit SSD1306', 'Adafruit LSM9DS1 Library',
- 'Adafruit Unified Sensor', 'List', 'Adafruit SGP30 Sensor', 'Adafruit_VL53L0X', 'Adafruit BMP280 Library', 'TM1637', 'LedControl'
-]
+ "Leaphy Original Extension",
+ "Leaphy Extra Extension",
+ "Servo",
+ "Adafruit GFX Library",
+ "Adafruit SSD1306",
+ "Adafruit LSM9DS1 Library",
+ "Adafruit Unified Sensor",
+ "List",
+ "Adafruit SGP30 Sensor",
+ "Adafruit_VL53L0X",
+ "Adafruit BMP280 Library",
+ "TM1637",
+ "LedControl",
+];
export const leaphyOriginalRobotType = new BaseUno(
- 'l_original_uno',
- 'Leaphy Original',
- 'orig.svg',
- 'orig_uno.svg',
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ "l_original_uno",
+ "Leaphy Original",
+ "orig.svg",
+ "orig_uno.svg",
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyActuators: true,
showLeaphyOperators: false,
@@ -19,13 +36,12 @@ export const leaphyOriginalRobotType = new BaseUno(
},
);
-
export const leaphyOriginalNanoRobotType = new BaseNano(
- 'l_original_nano',
- 'Original Nano',
- 'orig.svg',
- 'orig_nano.svg',
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ "l_original_nano",
+ "Original Nano",
+ "orig.svg",
+ "orig_nano.svg",
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyActuators: true,
showLeaphyOperators: true,
@@ -34,36 +50,36 @@ export const leaphyOriginalNanoRobotType = new BaseNano(
);
export const leaphyOriginalNanoESP32RobotType = new BaseNanoESP32(
- 'l_original_nano_esp32',
- 'Original Nano ESP32',
- 'orig.svg',
- 'orig_nano_esp32.svg',
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ "l_original_nano_esp32",
+ "Original Nano ESP32",
+ "orig.svg",
+ "orig_nano_esp32.svg",
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyActuators: true,
showLeaphyOperators: true,
showLeaphySensors: true,
},
-)
+);
export const leaphyOriginalNanoRP2040RobotType = new BaseNanoRP2040(
- 'l_original_nano_rp2040',
- 'Original Nano RP2040',
- 'orig.svg',
- 'orig_nano_rp2040.svg',
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ "l_original_nano_rp2040",
+ "Original Nano RP2040",
+ "orig.svg",
+ "orig_nano_rp2040.svg",
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyActuators: true,
showLeaphyOperators: true,
showLeaphySensors: true,
},
-)
+);
export const leaphyFlitzRobotType = new BaseUno(
- 'l_flitz_uno',
- 'Leaphy Flitz',
- 'flitz.svg',
- 'flitz_uno.svg',
+ "l_flitz_uno",
+ "Leaphy Flitz",
+ "flitz.svg",
+ "flitz_uno.svg",
defaultLibraries,
{
showLeaphyActuators: false,
@@ -72,10 +88,10 @@ export const leaphyFlitzRobotType = new BaseUno(
);
export const leaphyFlitzNanoRobotType = new BaseNano(
- 'l_flitz_nano',
- 'Flitz Nano',
- 'flitz.svg',
- 'flitz_nano.svg',
+ "l_flitz_nano",
+ "Flitz Nano",
+ "flitz.svg",
+ "flitz_nano.svg",
defaultLibraries,
{
showLeaphyActuators: false,
@@ -84,9 +100,9 @@ export const leaphyFlitzNanoRobotType = new BaseNano(
);
export const leaphyClickRobotType = new BaseUno(
- 'l_click',
- 'Leaphy Click',
- 'click.svg',
+ "l_click",
+ "Leaphy Click",
+ "click.svg",
null,
defaultLibraries,
{
@@ -95,11 +111,11 @@ export const leaphyClickRobotType = new BaseUno(
);
export const arduinoUnoRobotType = new BaseUno(
- 'l_uno',
- 'Arduino Uno',
- 'uno.svg',
+ "l_uno",
+ "Arduino Uno",
+ "uno.svg",
null,
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyLists: true,
showLeaphySensors: true,
@@ -107,20 +123,20 @@ export const arduinoUnoRobotType = new BaseUno(
);
export const genericRobotType = new BaseUno(
- 'l_code',
- 'Leaphy C++',
+ "l_code",
+ "Leaphy C++",
"c++.svg",
null,
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{},
);
export const arduinoNanoRobotType = new BaseNano(
- 'l_nano',
- 'Arduino Nano',
- 'nano.svg',
+ "l_nano",
+ "Arduino Nano",
+ "nano.svg",
null,
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyLists: true,
showLeaphySensors: true,
@@ -128,54 +144,55 @@ export const arduinoNanoRobotType = new BaseNano(
);
export const arduinoNanoESP32RobotType = new BaseNanoESP32(
- 'l_nano_esp32',
- 'Arduino Nano ESP32',
- 'nano.svg',
+ "l_nano_esp32",
+ "Arduino Nano ESP32",
+ "nano.svg",
null,
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyLists: true,
showLeaphySensors: true,
- }
+ },
);
export const arduinoNanoRP2040RobotType = new BaseNanoRP2040(
- 'l_nano_rp2040',
- 'Arduino Nano RP2040',
- 'nano.svg',
+ "l_nano_rp2040",
+ "Arduino Nano RP2040",
+ "nano.svg",
null,
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyLists: true,
showLeaphySensors: true,
- }
+ },
);
export const microPythonRobotType = new RobotType(
- 'l_micropython',
- {protocol: Avrdude},
- 'MicroPython',
- 'micropython.svg',
+ "l_micropython",
+ { protocol: Avrdude },
+ "MicroPython",
+ "micropython.svg",
null,
- '',
- '',
+ "",
+ "",
[],
{
showLeaphyActuators: false,
showLeaphyOperators: false,
- });
+ },
+);
export const arduinoMegaRobotType = new RobotType(
- 'l_mega',
- {protocol: Avrdude, microcontroller: 'atmega2560'},
- 'Arduino Mega',
- 'mega.svg',
+ "l_mega",
+ { protocol: Avrdude, microcontroller: "atmega2560" },
+ "Arduino Mega",
+ "mega.svg",
null,
- 'arduino:avr:mega',
- 'arduino:avr',
- defaultLibraries.concat(['QMC5883LCompass', 'Arduino_APDS9960']),
+ "arduino:avr:mega",
+ "arduino:avr",
+ defaultLibraries.concat(["QMC5883LCompass", "Arduino_APDS9960"]),
{
showLeaphyLists: true,
showLeaphySensors: true,
},
-)
+);
diff --git a/src/app/domain/snackbar.message.ts b/src/app/domain/snackbar.message.ts
index 6c4aebe1..e34612b4 100644
--- a/src/app/domain/snackbar.message.ts
+++ b/src/app/domain/snackbar.message.ts
@@ -1,3 +1,8 @@
export class SnackbarMessage {
- constructor(public event: string, public message: string, public payload: any, public displayTimeout: number) { }
+ constructor(
+ public event: string,
+ public message: string,
+ public payload: any,
+ public displayTimeout: number,
+ ) {}
}
diff --git a/src/app/effects/app.effects.ts b/src/app/effects/app.effects.ts
index 046ce670..ef23b66c 100644
--- a/src/app/effects/app.effects.ts
+++ b/src/app/effects/app.effects.ts
@@ -1,39 +1,38 @@
-import { Injectable } from '@angular/core';
-import { AppState } from '../state/app.state';
-import { TranslateService } from '@ngx-translate/core';
-import { filter, withLatestFrom } from 'rxjs/operators';
-import { Router } from '@angular/router';
-import { CodeEditorType } from '../domain/code-editor.type';
-import {LocalStorageService} from "../services/localstorage.service";
-import {MatDialog} from "@angular/material/dialog";
-import {ChangeLogDialog} from "../modules/core/dialogs/change-log/change-log.dialog";
+import { Injectable } from "@angular/core";
+import { AppState } from "../state/app.state";
+import { TranslateService } from "@ngx-translate/core";
+import { filter, withLatestFrom } from "rxjs/operators";
+import { Router } from "@angular/router";
+import { CodeEditorType } from "../domain/code-editor.type";
+import { LocalStorageService } from "../services/localstorage.service";
+import { MatDialog } from "@angular/material/dialog";
+import { ChangeLogDialog } from "../modules/core/dialogs/change-log/change-log.dialog";
import showdown from "showdown";
-import {WorkspaceService} from "../services/workspace.service";
+import { WorkspaceService } from "../services/workspace.service";
@Injectable({
- providedIn: 'root',
+ providedIn: "root",
})
-
export class AppEffects {
-
constructor(
private appState: AppState,
private translate: TranslateService,
private router: Router,
private localStorage: LocalStorageService,
private dialog: MatDialog,
- private workspaceService: WorkspaceService
+ private workspaceService: WorkspaceService,
) {
-
// Use the current language to translate the angular strings
this.appState.currentLanguage$
- .pipe(filter(language => !!language))
- .subscribe(language => this.translate.use(language.code));
-
+ .pipe(filter((language) => !!language))
+ .subscribe((language) => this.translate.use(language.code));
// When the editor change has been confirmed, toggle the code-editor
this.appState.isCodeEditorToggleConfirmed$
- .pipe(filter(isToggled => !!isToggled), withLatestFrom(this.appState.codeEditor$))
+ .pipe(
+ filter((isToggled) => !!isToggled),
+ withLatestFrom(this.appState.codeEditor$),
+ )
.subscribe(([, codeEditorType]) => {
if (codeEditorType == CodeEditorType.Beginner) {
this.appState.selectedCodeEditor = CodeEditorType.CPP;
@@ -44,17 +43,23 @@ export class AppEffects {
// When the code editor changes, route to the correct screen
this.appState.codeEditor$
- .pipe(filter(codeEditor => !!codeEditor))
- .subscribe(async codeEditor => {
+ .pipe(filter((codeEditor) => !!codeEditor))
+ .subscribe(async (codeEditor) => {
switch (codeEditor) {
case CodeEditorType.Beginner:
- await this.router.navigate(['/blocks'], { skipLocationChange: true });
+ await this.router.navigate(["/blocks"], {
+ skipLocationChange: true,
+ });
break;
case CodeEditorType.CPP:
- await this.router.navigate(['/cppEditor'], { skipLocationChange: true });
+ await this.router.navigate(["/cppEditor"], {
+ skipLocationChange: true,
+ });
break;
case CodeEditorType.Python:
- await this.router.navigate(['/pythonEditor'], { skipLocationChange: true });
+ await this.router.navigate(["/pythonEditor"], {
+ skipLocationChange: true,
+ });
break;
default:
break;
@@ -62,23 +67,23 @@ export class AppEffects {
this.appState.isCodeEditorToggleConfirmed = false;
});
-
-
this.appState.releaseInfo$
- .pipe(filter(releaseInfo => !!releaseInfo))
- .subscribe(releaseInfo => {
+ .pipe(filter((releaseInfo) => !!releaseInfo))
+ .subscribe((releaseInfo) => {
const releaseVersion = this.appState.releaseVersion;
if (!releaseVersion) {
return;
}
try {
- this.localStorage.fetch('releaseVersion');
+ this.localStorage.fetch("releaseVersion");
} catch (e) {
- this.localStorage.store('releaseVersion', '');
+ this.localStorage.store("releaseVersion", "");
}
- if (releaseVersion != this.localStorage.fetch('releaseVersion')) {
- let releaseNotes = releaseInfo["body"]
+ if (
+ releaseVersion != this.localStorage.fetch("releaseVersion")
+ ) {
+ let releaseNotes = releaseInfo["body"];
// convert all the urls to links
// first find the urls
let urls = releaseNotes.match(/(https?:\/\/[\S]+)/g);
@@ -86,10 +91,21 @@ export class AppEffects {
if (urls) {
// to prevent infinite loops we want to know the index of the last url we replaced
let lastUrlIndex = 0;
- urls.forEach(url => {
+ urls.forEach((url) => {
const link = `${url}`;
- releaseNotes = releaseNotes.substring(0, releaseNotes.indexOf(url, lastUrlIndex)) + link + releaseNotes.substring(releaseNotes.indexOf(url, lastUrlIndex) + url.length);
- lastUrlIndex = releaseNotes.indexOf(link, lastUrlIndex) + link.length;
+ releaseNotes =
+ releaseNotes.substring(
+ 0,
+ releaseNotes.indexOf(url, lastUrlIndex),
+ ) +
+ link +
+ releaseNotes.substring(
+ releaseNotes.indexOf(url, lastUrlIndex) +
+ url.length,
+ );
+ lastUrlIndex =
+ releaseNotes.indexOf(link, lastUrlIndex) +
+ link.length;
});
}
// turn the @mentions into links
@@ -97,9 +113,12 @@ export class AppEffects {
let mentions = releaseNotes.match(/@(\w+)/g);
// then replace them with links
if (mentions) {
- mentions.forEach(mention => {
+ mentions.forEach((mention) => {
const username = mention.substring(1);
- releaseNotes = releaseNotes.replaceAll(mention, `${mention}`);
+ releaseNotes = releaseNotes.replaceAll(
+ mention,
+ `${mention}`,
+ );
});
}
@@ -111,22 +130,20 @@ export class AppEffects {
data: {
title: releaseVersion,
message: releaseNotes,
- type: 'info'
- }
+ type: "info",
+ },
});
-
}
- this.localStorage.store('releaseVersion', releaseVersion);
+ this.localStorage.store("releaseVersion", releaseVersion);
- const robotId = this.localStorage.fetch('changedLanguage');
+ const robotId = this.localStorage.fetch("changedLanguage");
console.log(robotId);
if (robotId) {
- this.localStorage.store('changedLanguage', '');
- this.workspaceService.forceRestoreWorkspaceTemp().then(() => {});
+ this.localStorage.store("changedLanguage", "");
+ this.workspaceService
+ .forceRestoreWorkspaceTemp()
+ .then(() => {});
}
- })
-
+ });
}
-
-
}
diff --git a/src/app/effects/blockly-editor.effects.ts b/src/app/effects/blockly-editor.effects.ts
index 241f7421..8799de5b 100644
--- a/src/app/effects/blockly-editor.effects.ts
+++ b/src/app/effects/blockly-editor.effects.ts
@@ -1,149 +1,242 @@
-import {Injectable} from '@angular/core';
-import {BlocklyEditorState} from '../state/blockly-editor.state';
-import {filter, pairwise, withLatestFrom} from 'rxjs/operators';
-import {HttpClient, HttpHeaders} from '@angular/common/http';
-import {combineLatest, Observable} from 'rxjs';
-import {AppState} from '../state/app.state';
-import {CodeEditorType} from '../domain/code-editor.type';
-import * as Blockly from 'blockly';
-import '@blockly/field-bitmap'
-
-import {CATEGORIES, THEME, EXTENSIONS, translations, arduino, getBlocks} from "@leaphy-robotics/leaphy-blocks"
-import {LeaphyCategory} from "../services/toolbox/category";
-import {LeaphyToolbox} from "../services/toolbox/toolbox";
-import {CodeEditorState} from "../state/code-editor.state";
-import {genericRobotType, microPythonRobotType} from "../domain/robots";
-import {RobotType} from "../domain/robot.type";
-import {WorkspaceService} from "../services/workspace.service";
-import {LocalStorageService} from "../services/localstorage.service";
+import { Injectable } from "@angular/core";
+import { BlocklyEditorState } from "../state/blockly-editor.state";
+import { filter, pairwise, withLatestFrom } from "rxjs/operators";
+import { HttpClient, HttpHeaders } from "@angular/common/http";
+import { combineLatest, Observable } from "rxjs";
+import { AppState } from "../state/app.state";
+import { CodeEditorType } from "../domain/code-editor.type";
+import * as Blockly from "blockly";
+import "@blockly/field-bitmap";
+
+import {
+ CATEGORIES,
+ THEME,
+ EXTENSIONS,
+ translations,
+ arduino,
+ getBlocks,
+} from "@leaphy-robotics/leaphy-blocks";
+import { LeaphyCategory } from "../services/toolbox/category";
+import { LeaphyToolbox } from "../services/toolbox/toolbox";
+import { CodeEditorState } from "../state/code-editor.state";
+import { genericRobotType, microPythonRobotType } from "../domain/robots";
+import { RobotType } from "../domain/robot.type";
+import { WorkspaceService } from "../services/workspace.service";
+import { LocalStorageService } from "../services/localstorage.service";
@Injectable({
- providedIn: 'root',
+ providedIn: "root",
})
// Defines the effects on the Blockly Editor that different state changes have
export class BlocklyEditorEffects {
-
constructor(
private blocklyState: BlocklyEditorState,
private appState: AppState,
private codeEditorState: CodeEditorState,
private http: HttpClient,
private workspaceService: WorkspaceService,
- private localStorage: LocalStorageService
+ private localStorage: LocalStorageService,
) {
Blockly.registry.register(
Blockly.registry.Type.TOOLBOX_ITEM,
Blockly.ToolboxCategory.registrationName,
- LeaphyCategory, true);
- Blockly.registry.register(Blockly.registry.Type.TOOLBOX, Blockly.CollapsibleToolboxCategory.registrationName, LeaphyToolbox);
- Blockly.registry.register(Blockly.registry.Type.SERIALIZER, "lists", new CATEGORIES.ListSerializer())
+ LeaphyCategory,
+ true,
+ );
+ Blockly.registry.register(
+ Blockly.registry.Type.TOOLBOX,
+ Blockly.CollapsibleToolboxCategory.registrationName,
+ LeaphyToolbox,
+ );
+ Blockly.registry.register(
+ Blockly.registry.Type.SERIALIZER,
+ "lists",
+ new CATEGORIES.ListSerializer(),
+ );
- Blockly.Extensions.register('appendStatementInputStack', EXTENSIONS.APPEND_STATEMENT_INPUT_STACK)
- Blockly.Extensions.register('list_select_extension', EXTENSIONS.LIST_SELECT_EXTENSION);
+ Blockly.Extensions.register(
+ "appendStatementInputStack",
+ EXTENSIONS.APPEND_STATEMENT_INPUT_STACK,
+ );
+ Blockly.Extensions.register(
+ "list_select_extension",
+ EXTENSIONS.LIST_SELECT_EXTENSION,
+ );
Blockly.Extensions.registerMutator(
- 'l_controls_if_mutator',
+ "l_controls_if_mutator",
EXTENSIONS.CONTROLS_IF_MUTATOR_MIXIN,
null as unknown as undefined, // TODO(#6920)
- ['controls_if_elseif', 'controls_if_else'],
+ ["controls_if_elseif", "controls_if_else"],
);
// When the current language is set: Find and set the blockly translations
this.appState.currentLanguage$
- .pipe(filter(language => !!language))
- .subscribe(async language => {
+ .pipe(filter((language) => !!language))
+ .subscribe(async (language) => {
Blockly.setLocale(translations[language.code]);
});
// When the language is changed, save the workspace temporarily
this.appState.changedLanguage$
- .pipe(filter(language => !!language))
- .pipe(withLatestFrom(this.blocklyState.workspaceJSON$, this.appState.selectedRobotType$))
+ .pipe(filter((language) => !!language))
+ .pipe(
+ withLatestFrom(
+ this.blocklyState.workspaceJSON$,
+ this.appState.selectedRobotType$,
+ ),
+ )
.subscribe(([, workspaceXml]) => {
- this.workspaceService.saveWorkspaceTemp(workspaceXml).then(() => {});
- this.localStorage.store("changedLanguage", this.appState.selectedRobotType.id);
+ this.workspaceService
+ .saveWorkspaceTemp(workspaceXml)
+ .then(() => {});
+ this.localStorage.store(
+ "changedLanguage",
+ this.appState.selectedRobotType.id,
+ );
});
// When all prerequisites are there, Create a new workspace and open the codeview if needed
- combineLatest([this.blocklyState.blocklyElement$, this.blocklyState.blocklyConfig$])
+ combineLatest([
+ this.blocklyState.blocklyElement$,
+ this.blocklyState.blocklyConfig$,
+ ])
.pipe(withLatestFrom(this.appState.selectedRobotType$))
- .pipe(filter(([[element, config], robotType]) => !!element && !!config && !!robotType && (robotType !== genericRobotType && robotType !== microPythonRobotType)))
- .pipe(withLatestFrom(
- this.getXmlContent('./assets/blockly/base-toolbox.xml'),
- this.getXmlContent('./assets/blockly/leaphy-toolbox.xml'),
- this.getXmlContent('./assets/blockly/leaphy-start.xml')
- ))
- .subscribe(([[[element, config], robotType], baseToolboxXml, leaphyToolboxXml, startWorkspaceXml]) => {
- const leaphyBlocks = getBlocks(this.appState.selectedRobotType.id);
- Blockly.defineBlocksWithJsonArray(leaphyBlocks.block)
- config.theme = Blockly.Theme.defineTheme('leaphy', {
- 'blockStyles': THEME.defaultBlockStyles,
- 'categoryStyles': THEME.categoryStyles,
- 'componentStyles': THEME.componentStyles,
- name: 'leaphy',
- });
- const toolboxXmlString = this.loadToolBox(baseToolboxXml, leaphyToolboxXml, robotType);
- config.toolbox = toolboxXmlString;
- // @ts-ignore
- const workspace = Blockly.inject(element, config);
- const toolbox = workspace.getToolbox();
- workspace.registerToolboxCategoryCallback('LISTS', CATEGORIES.LISTS);
- toolbox.getFlyout().autoClose = false;
- const xml = Blockly.utils.xml.textToDom(startWorkspaceXml);
- Blockly.Xml.domToWorkspace(xml, workspace);
- this.blocklyState.workspace = workspace;
- this.blocklyState.toolboxXml = toolboxXmlString;
- if (this.appState.currentEditor == CodeEditorType.Beginner) {
- this.workspaceService.restoreWorkspaceTemp().then(() => {});
- }
- toolbox.selectItemByPosition(0);
- toolbox.refreshTheme();
-
- setTimeout(() => this.blocklyState.isSideNavOpen = robotType.features.showCodeOnStart, 200);
- });
+ .pipe(
+ filter(
+ ([[element, config], robotType]) =>
+ !!element &&
+ !!config &&
+ !!robotType &&
+ robotType !== genericRobotType &&
+ robotType !== microPythonRobotType,
+ ),
+ )
+ .pipe(
+ withLatestFrom(
+ this.getXmlContent("./assets/blockly/base-toolbox.xml"),
+ this.getXmlContent("./assets/blockly/leaphy-toolbox.xml"),
+ this.getXmlContent("./assets/blockly/leaphy-start.xml"),
+ ),
+ )
+ .subscribe(
+ ([
+ [[element, config], robotType],
+ baseToolboxXml,
+ leaphyToolboxXml,
+ startWorkspaceXml,
+ ]) => {
+ const leaphyBlocks = getBlocks(
+ this.appState.selectedRobotType.id,
+ );
+ Blockly.defineBlocksWithJsonArray(leaphyBlocks.block);
+ config.theme = Blockly.Theme.defineTheme("leaphy", {
+ blockStyles: THEME.defaultBlockStyles,
+ categoryStyles: THEME.categoryStyles,
+ componentStyles: THEME.componentStyles,
+ name: "leaphy",
+ });
+ const toolboxXmlString = this.loadToolBox(
+ baseToolboxXml,
+ leaphyToolboxXml,
+ robotType,
+ );
+ config.toolbox = toolboxXmlString;
+ // @ts-ignore
+ const workspace = Blockly.inject(element, config);
+ const toolbox = workspace.getToolbox();
+ workspace.registerToolboxCategoryCallback(
+ "LISTS",
+ CATEGORIES.LISTS,
+ );
+ toolbox.getFlyout().autoClose = false;
+ const xml = Blockly.utils.xml.textToDom(startWorkspaceXml);
+ Blockly.Xml.domToWorkspace(xml, workspace);
+ this.blocklyState.workspace = workspace;
+ this.blocklyState.toolboxXml = toolboxXmlString;
+ if (
+ this.appState.currentEditor == CodeEditorType.Beginner
+ ) {
+ this.workspaceService
+ .restoreWorkspaceTemp()
+ .then(() => {});
+ }
+ toolbox.selectItemByPosition(0);
+ toolbox.refreshTheme();
+
+ setTimeout(
+ () =>
+ (this.blocklyState.isSideNavOpen =
+ robotType.features.showCodeOnStart),
+ 200,
+ );
+ },
+ );
// When a new project is started, reset the blockly code
this.appState.selectedRobotType$
- .pipe(filter(robotType => !robotType))
- .subscribe(() => this.codeEditorState.code = '')
+ .pipe(filter((robotType) => !robotType))
+ .subscribe(() => (this.codeEditorState.code = ""));
// When the robot selection changes, set the toolbox and initialWorkspace
this.appState.selectedRobotType$
.pipe(withLatestFrom(this.blocklyState.workspace$))
- .pipe(filter(([robotType, workspace]) => !!robotType && !!workspace))
- .pipe(withLatestFrom(
- this.getXmlContent('./assets/blockly/base-toolbox.xml'),
- this.getXmlContent('./assets/blockly/leaphy-toolbox.xml'),
- this.getXmlContent('./assets/blockly/leaphy-start.xml'),
- ))
- .subscribe(([[robotType, workspace], baseToolboxXml, leaphyToolboxXml, startWorkspaceXml]) => {
- const toolboxXmlString = this.loadToolBox(baseToolboxXml, leaphyToolboxXml, robotType);
- this.blocklyState.toolboxXml = toolboxXmlString;
-
- workspace.clear();
- const xml = Blockly.utils.xml.textToDom(startWorkspaceXml);
- Blockly.Xml.domToWorkspace(xml, workspace);
- });
+ .pipe(
+ filter(([robotType, workspace]) => !!robotType && !!workspace),
+ )
+ .pipe(
+ withLatestFrom(
+ this.getXmlContent("./assets/blockly/base-toolbox.xml"),
+ this.getXmlContent("./assets/blockly/leaphy-toolbox.xml"),
+ this.getXmlContent("./assets/blockly/leaphy-start.xml"),
+ ),
+ )
+ .subscribe(
+ ([
+ [robotType, workspace],
+ baseToolboxXml,
+ leaphyToolboxXml,
+ startWorkspaceXml,
+ ]) => {
+ const toolboxXmlString = this.loadToolBox(
+ baseToolboxXml,
+ leaphyToolboxXml,
+ robotType,
+ );
+ this.blocklyState.toolboxXml = toolboxXmlString;
+
+ workspace.clear();
+ const xml = Blockly.utils.xml.textToDom(startWorkspaceXml);
+ Blockly.Xml.domToWorkspace(xml, workspace);
+ },
+ );
// Update the toolbox when it changes
this.blocklyState.toolboxXml$
.pipe(withLatestFrom(this.blocklyState.workspace$))
.pipe(filter(([toolbox, workspace]) => !!toolbox && !!workspace))
- .subscribe(([toolbox, workspace]) => workspace.updateToolbox(toolbox))
+ .subscribe(([toolbox, workspace]) =>
+ workspace.updateToolbox(toolbox),
+ );
// Subscribe to changes when the workspace is set
this.blocklyState.workspace$
- .pipe(filter(workspace => !!workspace))
- .subscribe(workspace => {
+ .pipe(filter((workspace) => !!workspace))
+ .subscribe((workspace) => {
workspace.clearUndo();
workspace.addChangeListener(Blockly.Events.disableOrphans);
workspace.addChangeListener(async () => {
- if (this.appState.currentEditor !== CodeEditorType.Beginner) return;
- this.codeEditorState.code = arduino.workspaceToCode(workspace, this.appState.selectedRobotType.id);
- this.blocklyState.workspaceJSON = JSON.stringify(Blockly.serialization.workspaces.save(workspace));
+ if (this.appState.currentEditor !== CodeEditorType.Beginner)
+ return;
+ this.codeEditorState.code = arduino.workspaceToCode(
+ workspace,
+ this.appState.selectedRobotType.id,
+ );
+ this.blocklyState.workspaceJSON = JSON.stringify(
+ Blockly.serialization.workspaces.save(workspace),
+ );
});
-
});
// When the user presses undo or redo, trigger undo or redo on the workspace
@@ -152,12 +245,16 @@ export class BlocklyEditorEffects {
.pipe(filter(([, workspace]) => !!workspace))
.subscribe(([redo, workspace]) => workspace.undo(redo));
-
// When Advanced CodeEditor is Selected, hide the sideNav
this.appState.codeEditor$
.pipe(
pairwise(),
- filter(([previous, current]) => (current === CodeEditorType.CPP || current === CodeEditorType.Python ) && current !== previous)
+ filter(
+ ([previous, current]) =>
+ (current === CodeEditorType.CPP ||
+ current === CodeEditorType.Python) &&
+ current !== previous,
+ ),
)
.subscribe(() => {
this.blocklyState.isSideNavOpen = false;
@@ -165,7 +262,10 @@ export class BlocklyEditorEffects {
// Toggle the isSoundOn state
this.blocklyState.isSoundToggled$
- .pipe(filter(isToggled => !!isToggled), withLatestFrom(this.blocklyState.isSoundOn$))
+ .pipe(
+ filter((isToggled) => !!isToggled),
+ withLatestFrom(this.blocklyState.isSoundOn$),
+ )
.subscribe(([, isSoundOn]) => {
this.blocklyState.isSoundOn = !isSoundOn;
});
@@ -178,7 +278,10 @@ export class BlocklyEditorEffects {
basePlay = Blockly.WorkspaceAudio.prototype.play;
this.blocklyState.playSoundFunction = basePlay;
}
- Blockly.WorkspaceAudio.prototype.play = function (name, opt_volume) {
+ Blockly.WorkspaceAudio.prototype.play = function (
+ name,
+ opt_volume,
+ ) {
if (isSoundOn) {
basePlay.call(this, name, opt_volume);
}
@@ -186,67 +289,107 @@ export class BlocklyEditorEffects {
});
// When the code editor is changed, clear the projectFilePath
- this.appState.codeEditor$
- .subscribe(() => this.blocklyState.projectFileHandle = null);
+ this.appState.codeEditor$.subscribe(
+ () => (this.blocklyState.projectFileHandle = null),
+ );
}
- private parseCategory(root: Document, category: HTMLElement, robotType: RobotType,) : HTMLElement {
+ private parseCategory(
+ root: Document,
+ category: HTMLElement,
+ robotType: RobotType,
+ ): HTMLElement {
// Remove blocks that aren't in robots list
- Array.from(category.querySelectorAll('block'))
- .filter(block => {
- const robots = block.querySelector('robots');
+ Array.from(category.querySelectorAll("block"))
+ .filter((block) => {
+ const robots = block.querySelector("robots");
if (!robots) return false;
block.removeChild(robots);
return !robots.querySelector(robotType.id);
})
- .forEach(block => block.remove());
+ .forEach((block) => block.remove());
// Add separator between groups
- Array.from(category.querySelectorAll('group'))
- .forEach(group => {
- const items = Array.from(group.querySelectorAll('block'))
- .map((block, index, array) => {
- if (index === array.length - 1) return block
-
- const separator = root.createElement('sep')
- separator.setAttribute('gap', '8')
- return [block, separator]
- })
- .flat()
-
- group.before(...items)
- group.remove()
- })
-
- return category
+ Array.from(category.querySelectorAll("group")).forEach((group) => {
+ const items = Array.from(group.querySelectorAll("block"))
+ .map((block, index, array) => {
+ if (index === array.length - 1) return block;
+
+ const separator = root.createElement("sep");
+ separator.setAttribute("gap", "8");
+ return [block, separator];
+ })
+ .flat();
+
+ group.before(...items);
+ group.remove();
+ });
+
+ return category;
}
- private loadToolBox(baseToolboxXml: string, leaphyToolboxXml: string, robotType: RobotType) : string {
+ private loadToolBox(
+ baseToolboxXml: string,
+ leaphyToolboxXml: string,
+ robotType: RobotType,
+ ): string {
const parser = new DOMParser();
- const toolboxXmlDoc = parser.parseFromString(baseToolboxXml, 'text/xml');
- const toolboxElement = toolboxXmlDoc.getElementById('easyBloqsToolbox');
- const leaphyCategories = parser.parseFromString(leaphyToolboxXml, 'text/xml');
- const leaphyRobotCategory = leaphyCategories.getElementById(robotType.id);
+ const toolboxXmlDoc = parser.parseFromString(
+ baseToolboxXml,
+ "text/xml",
+ );
+ const toolboxElement = toolboxXmlDoc.getElementById("easyBloqsToolbox");
+ const leaphyCategories = parser.parseFromString(
+ leaphyToolboxXml,
+ "text/xml",
+ );
+ const leaphyRobotCategory = leaphyCategories.getElementById(
+ robotType.id,
+ );
if (robotType.features.showLeaphyOperators) {
- toolboxElement.removeChild(toolboxXmlDoc.getElementById("l_numbers"))
+ toolboxElement.removeChild(
+ toolboxXmlDoc.getElementById("l_numbers"),
+ );
} else {
- toolboxElement.removeChild(toolboxXmlDoc.getElementById("l_operators"))
+ toolboxElement.removeChild(
+ toolboxXmlDoc.getElementById("l_operators"),
+ );
}
if (robotType.features.showLeaphyActuators) {
- const leaphyExtraCategory = leaphyCategories.getElementById("l_actuators");
- leaphyExtraCategory.setAttribute("toolboxitemid", `${robotType.id}_actuators`)
-
- toolboxElement.prepend(this.parseCategory(leaphyCategories, leaphyExtraCategory, robotType));
+ const leaphyExtraCategory =
+ leaphyCategories.getElementById("l_actuators");
+ leaphyExtraCategory.setAttribute(
+ "toolboxitemid",
+ `${robotType.id}_actuators`,
+ );
+
+ toolboxElement.prepend(
+ this.parseCategory(
+ leaphyCategories,
+ leaphyExtraCategory,
+ robotType,
+ ),
+ );
}
if (robotType.features.showLeaphySensors) {
- const leaphySensorCategory = leaphyCategories.getElementById("l_sensors");
- leaphySensorCategory.setAttribute("toolboxitemid", `${robotType.id}_sensors`);
-
- toolboxElement.prepend(this.parseCategory(leaphyCategories, leaphySensorCategory, robotType));
+ const leaphySensorCategory =
+ leaphyCategories.getElementById("l_sensors");
+ leaphySensorCategory.setAttribute(
+ "toolboxitemid",
+ `${robotType.id}_sensors`,
+ );
+
+ toolboxElement.prepend(
+ this.parseCategory(
+ leaphyCategories,
+ leaphySensorCategory,
+ robotType,
+ ),
+ );
}
if (!robotType.features.showLeaphyLists) {
- toolboxElement.removeChild(toolboxXmlDoc.getElementById("l_lists"))
+ toolboxElement.removeChild(toolboxXmlDoc.getElementById("l_lists"));
}
if (leaphyRobotCategory) {
toolboxElement.prepend(leaphyRobotCategory);
@@ -256,15 +399,16 @@ export class BlocklyEditorEffects {
}
private getXmlContent(path: string): Observable {
- return this.http
- .get(path, {
- headers: new HttpHeaders()
- .set('Content-Type', 'text/xml')
- .append('Access-Control-Allow-Methods', 'GET')
- .append('Access-Control-Allow-Origin', '*')
- .append('Access-Control-Allow-Headers',
- 'Access-Control-Allow-Headers, Access-Control-Allow-Origin, Access-Control-Request-Method'),
- responseType: 'text'
- })
+ return this.http.get(path, {
+ headers: new HttpHeaders()
+ .set("Content-Type", "text/xml")
+ .append("Access-Control-Allow-Methods", "GET")
+ .append("Access-Control-Allow-Origin", "*")
+ .append(
+ "Access-Control-Allow-Headers",
+ "Access-Control-Allow-Headers, Access-Control-Allow-Origin, Access-Control-Request-Method",
+ ),
+ responseType: "text",
+ });
}
}
diff --git a/src/app/effects/code-editor.effects.ts b/src/app/effects/code-editor.effects.ts
index 41300c82..38503211 100644
--- a/src/app/effects/code-editor.effects.ts
+++ b/src/app/effects/code-editor.effects.ts
@@ -1,35 +1,34 @@
-import {Injectable} from "@angular/core";
-import {CodeEditorState} from "../state/code-editor.state";
-import {AppState} from "../state/app.state";
-import {CodeEditorType} from "../domain/code-editor.type";
-import {genericRobotType} from "../domain/robots";
-import {WorkspaceService} from "../services/workspace.service";
-
+import { Injectable } from "@angular/core";
+import { CodeEditorState } from "../state/code-editor.state";
+import { AppState } from "../state/app.state";
+import { CodeEditorType } from "../domain/code-editor.type";
+import { genericRobotType } from "../domain/robots";
+import { WorkspaceService } from "../services/workspace.service";
@Injectable({
- providedIn: 'root',
+ providedIn: "root",
})
// Defines the effects on the Editor that different state changes have
export class CodeEditorEffects {
-
constructor(
private codeEditorState: CodeEditorState,
private appState: AppState,
private workspaceService: WorkspaceService,
) {
- this.appState.codeEditor$
- .subscribe(codeEditor => {
- console.log('codeEditor', codeEditor);
- if (codeEditor == CodeEditorType.Python) {
- this.codeEditorState.code = `from leaphymicropython.utils.pins import set_pwm`;
- this.workspaceService.restoreWorkspaceTemp().then(() => {});
- } else if (codeEditor == CodeEditorType.CPP && this.appState.selectedRobotType == genericRobotType) {
- this.codeEditorState.code = this.codeEditorState.code = `void leaphyProgram() {\n\n}\n\nvoid setup() {\n leaphyProgram();\n}\n\nvoid loop() {\n\n}`;
- this.workspaceService.restoreWorkspaceTemp().then(() => {});
- }
- });
+ this.appState.codeEditor$.subscribe((codeEditor) => {
+ console.log("codeEditor", codeEditor);
+ if (codeEditor == CodeEditorType.Python) {
+ this.codeEditorState.code = `from leaphymicropython.utils.pins import set_pwm`;
+ this.workspaceService.restoreWorkspaceTemp().then(() => {});
+ } else if (
+ codeEditor == CodeEditorType.CPP &&
+ this.appState.selectedRobotType == genericRobotType
+ ) {
+ this.codeEditorState.code =
+ this.codeEditorState.code = `void leaphyProgram() {\n\n}\n\nvoid setup() {\n leaphyProgram();\n}\n\nvoid loop() {\n\n}`;
+ this.workspaceService.restoreWorkspaceTemp().then(() => {});
+ }
+ });
}
-
-
}
diff --git a/src/app/effects/dialog.effects.ts b/src/app/effects/dialog.effects.ts
index 903b52b9..6c99ff2b 100644
--- a/src/app/effects/dialog.effects.ts
+++ b/src/app/effects/dialog.effects.ts
@@ -1,40 +1,39 @@
-import { Injectable } from '@angular/core';
-import { MatDialog } from '@angular/material/dialog';
-import { filter } from 'rxjs/operators';
-import { DialogState } from '../state/dialog.state';
-import { CreditsDialog } from '../modules/core/dialogs/credits/credits.dialog';
-import { InfoDialog } from '../modules/core/dialogs/info/info.dialog';
-import { ConfirmEditorDialog } from '../modules/core/dialogs/confirm-editor/confirm-editor.dialog';
-import { LanguageSelectDialog } from '../modules/core/dialogs/language-select/language-select.dialog';
-import {SerialOutputComponent} from "../modules/shared/components/serial-output/serial-output.component";
-import {AppState} from "../state/app.state";
-import {LibraryManagerComponent} from "../modules/shared/components/library-manager/library-manager.component";
-import {ExamplesDialog} from "../modules/core/dialogs/examples/examples-dialog.component";
+import { Injectable } from "@angular/core";
+import { MatDialog } from "@angular/material/dialog";
+import { filter } from "rxjs/operators";
+import { DialogState } from "../state/dialog.state";
+import { CreditsDialog } from "../modules/core/dialogs/credits/credits.dialog";
+import { InfoDialog } from "../modules/core/dialogs/info/info.dialog";
+import { ConfirmEditorDialog } from "../modules/core/dialogs/confirm-editor/confirm-editor.dialog";
+import { LanguageSelectDialog } from "../modules/core/dialogs/language-select/language-select.dialog";
+import { SerialOutputComponent } from "../modules/shared/components/serial-output/serial-output.component";
+import { AppState } from "../state/app.state";
+import { LibraryManagerComponent } from "../modules/shared/components/library-manager/library-manager.component";
+import { ExamplesDialog } from "../modules/core/dialogs/examples/examples-dialog.component";
@Injectable({
- providedIn: 'root',
+ providedIn: "root",
})
// Defines the effects on the Dialog that different state changes have
export class DialogEffects {
-
constructor(
private appState: AppState,
private dialogState: DialogState,
private dialog: MatDialog,
) {
this.dialogState.isExamplesDialogVisible$
- .pipe(filter(isVisible => !!isVisible))
+ .pipe(filter((isVisible) => !!isVisible))
.subscribe(() => {
this.dialog.open(ExamplesDialog, {
width: "800px",
disableClose: true,
- })
- })
+ });
+ });
// When the info dialog visibility is set to true, open the dialog
this.dialogState.isInfoDialogVisible$
- .pipe(filter(isVisible => !!isVisible))
+ .pipe(filter((isVisible) => !!isVisible))
.subscribe(() => {
this.dialog.open(InfoDialog, {
width: "800px",
@@ -43,54 +42,69 @@ export class DialogEffects {
});
// If the isSerialOutputWindowOpen is set to true open the dialog
- this.dialogState.isSerialOutputWindowOpen$
- .subscribe(() => {
- if (this.dialogState.isSerialOutputWindowOpen !== true)
- return;
- this.dialog.open(SerialOutputComponent, {
+ this.dialogState.isSerialOutputWindowOpen$.subscribe(() => {
+ if (this.dialogState.isSerialOutputWindowOpen !== true) return;
+ this.dialog
+ .open(SerialOutputComponent, {
width: "800px",
disableClose: true,
hasBackdrop: false,
- }).afterClosed().subscribe(() => {
+ })
+ .afterClosed()
+ .subscribe(() => {
this.dialogState.isSerialOutputWindowOpen = false;
});
- });
-
+ });
// If the isLibraryManagerWindowOpen is set to true open the dialog
- this.dialogState.isLibraryManagerWindowOpen$
- .subscribe(() => {
- if (this.dialogState.isLibraryManagerWindowOpen !== true)
- return;
- this.dialog.open(LibraryManagerComponent, {
+ this.dialogState.isLibraryManagerWindowOpen$.subscribe(() => {
+ if (this.dialogState.isLibraryManagerWindowOpen !== true) return;
+ this.dialog
+ .open(LibraryManagerComponent, {
disableClose: true,
- }).afterClosed().subscribe(() => {
+ })
+ .afterClosed()
+ .subscribe(() => {
this.dialogState.isLibraryManagerWindowOpen = false;
});
- });
+ });
- const language = localStorage.getItem('currentLanguage');
+ const language = localStorage.getItem("currentLanguage");
if (!language) {
const languageDialogRef = this.dialog.open(LanguageSelectDialog, {
- width: '450px',
+ width: "450px",
disableClose: true,
});
languageDialogRef.afterClosed().subscribe(() => {
- this.dialog.open(CreditsDialog, {
- width: '800px',
- disableClose: true,
- }).afterClosed().subscribe(() => {
- (async () => {
- if (localStorage.getItem("showReleaseNotes") === "0") return
- this.appState.releaseInfoSubject$.next(await fetch("https://api.github.com/repos/leaphy-robotics/leaphy-webbased/releases/latest").then(response => response.json()));
- })();
- });
+ this.dialog
+ .open(CreditsDialog, {
+ width: "800px",
+ disableClose: true,
+ })
+ .afterClosed()
+ .subscribe(() => {
+ (async () => {
+ if (
+ localStorage.getItem("showReleaseNotes") === "0"
+ )
+ return;
+ this.appState.releaseInfoSubject$.next(
+ await fetch(
+ "https://api.github.com/repos/leaphy-robotics/leaphy-webbased/releases/latest",
+ ).then((response) => response.json()),
+ );
+ })();
+ });
});
} else {
(async () => {
- if (localStorage.getItem("showReleaseNotes") === "0") return
- this.appState.releaseInfoSubject$.next(await fetch("https://api.github.com/repos/leaphy-robotics/leaphy-webbased/releases/latest").then(response => response.json()));
+ if (localStorage.getItem("showReleaseNotes") === "0") return;
+ this.appState.releaseInfoSubject$.next(
+ await fetch(
+ "https://api.github.com/repos/leaphy-robotics/leaphy-webbased/releases/latest",
+ ).then((response) => response.json()),
+ );
})();
}
}
diff --git a/src/app/effects/robot.wired.effects.ts b/src/app/effects/robot.wired.effects.ts
index 9ea48705..ba0a74f6 100644
--- a/src/app/effects/robot.wired.effects.ts
+++ b/src/app/effects/robot.wired.effects.ts
@@ -1,15 +1,14 @@
-import { Injectable } from '@angular/core';
-import { filter } from 'rxjs/operators';
-import { RobotWiredState } from '../state/robot.wired.state';
-import {DialogState} from "../state/dialog.state";
+import { Injectable } from "@angular/core";
+import { filter } from "rxjs/operators";
+import { RobotWiredState } from "../state/robot.wired.state";
+import { DialogState } from "../state/dialog.state";
import ArduinoUploader from "../services/arduino-uploader/ArduinoUploader";
-import {AppState} from "../state/app.state";
-import {UploadState} from "../state/upload.state";
+import { AppState } from "../state/app.state";
+import { UploadState } from "../state/upload.state";
@Injectable({
- providedIn: 'root',
+ providedIn: "root",
})
-
export class RobotWiredEffects {
private webserial: ArduinoUploader;
private logBuffer: string = "";
@@ -20,13 +19,16 @@ export class RobotWiredEffects {
private uploadState: UploadState,
private dialogState: DialogState,
) {
- this.webserial = new ArduinoUploader(this.robotWiredState, this.appState, this.uploadState);
+ this.webserial = new ArduinoUploader(
+ this.robotWiredState,
+ this.appState,
+ this.uploadState,
+ );
this.dialogState.isSerialOutputListening$
- .pipe(filter(isListening => !!isListening))
+ .pipe(filter((isListening) => !!isListening))
.subscribe(async () => {
- if (this.robotWiredState.pythonDeviceConnected)
- return;
+ if (this.robotWiredState.pythonDeviceConnected) return;
const robotWiredState = this.robotWiredState;
const outputStream = new WritableStream({
@@ -34,18 +36,23 @@ export class RobotWiredEffects {
this.logBuffer = "";
},
write: async (chunk) => {
- this.logBuffer += new TextDecoder("utf-8").decode(chunk);
+ this.logBuffer += new TextDecoder("utf-8").decode(
+ chunk,
+ );
const date = new Date();
- function makeString (chunkedStr: string) {
- robotWiredState.incomingSerialData = { time: date, data: chunkedStr };
+ function makeString(chunkedStr: string) {
+ robotWiredState.incomingSerialData = {
+ time: date,
+ data: chunkedStr,
+ };
}
let i = this.logBuffer.indexOf("\n");
await new Promise((resolve) => {
// Give the browser time to render/update the dialog
- setTimeout(resolve, 1)
- })
+ setTimeout(resolve, 1);
+ });
while (i != -1) {
let part = this.logBuffer.slice(0, i);
this.logBuffer = this.logBuffer.slice(i + 1);
@@ -65,6 +72,4 @@ export class RobotWiredEffects {
this.webserial.serialMonitor(outputStream).then(() => {});
});
}
-
-
}
diff --git a/src/app/modules/blockly-editor/blockly-editor.module.ts b/src/app/modules/blockly-editor/blockly-editor.module.ts
index 7d54b254..f9cefe90 100644
--- a/src/app/modules/blockly-editor/blockly-editor.module.ts
+++ b/src/app/modules/blockly-editor/blockly-editor.module.ts
@@ -1,18 +1,14 @@
-import { NgModule } from '@angular/core';
-import { CommonModule } from '@angular/common';
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
-import { LeaphyBlocklyComponent } from './components/leaphy-blockly/leaphy-blockly.component';
-import { CodeViewComponent } from './components/code-view/code-view.component';
-import { SharedModule } from '../shared/shared.module';
-import {MonacoEditorModule} from "ngx-monaco-editor-v2";
+import { LeaphyBlocklyComponent } from "./components/leaphy-blockly/leaphy-blockly.component";
+import { CodeViewComponent } from "./components/code-view/code-view.component";
+import { SharedModule } from "../shared/shared.module";
+import { MonacoEditorModule } from "ngx-monaco-editor-v2";
@NgModule({
declarations: [LeaphyBlocklyComponent, CodeViewComponent],
- imports: [
- CommonModule,
- SharedModule,
- MonacoEditorModule
- ],
+ imports: [CommonModule, SharedModule, MonacoEditorModule],
exports: [LeaphyBlocklyComponent, CodeViewComponent],
})
-export class BlocklyEditorModule { }
+export class BlocklyEditorModule {}
diff --git a/src/app/modules/blockly-editor/blockly-editor.page.html b/src/app/modules/blockly-editor/blockly-editor.page.html
index 57818636..8b57ae70 100644
--- a/src/app/modules/blockly-editor/blockly-editor.page.html
+++ b/src/app/modules/blockly-editor/blockly-editor.page.html
@@ -3,9 +3,16 @@
-
+
-
+
diff --git a/src/app/modules/blockly-editor/blockly-editor.page.scss b/src/app/modules/blockly-editor/blockly-editor.page.scss
index 805701c9..9d34ef94 100644
--- a/src/app/modules/blockly-editor/blockly-editor.page.scss
+++ b/src/app/modules/blockly-editor/blockly-editor.page.scss
@@ -1,32 +1,32 @@
#container {
- display: flex;
- flex-direction: row;
- align-items: stretch;
- height: calc(100% - 64px);
- width: 100%;
- overflow: hidden;
+ display: flex;
+ flex-direction: row;
+ align-items: stretch;
+ height: calc(100% - 64px);
+ width: 100%;
+ overflow: hidden;
}
.sidenav-container {
- flex: 1 1 auto;
- background: #eee;
+ flex: 1 1 auto;
+ background: #eee;
}
#sidenav {
- height: 100%;
- width: 20%;
+ height: 100%;
+ width: 20%;
}
app-code-view {
- display: block;
- height: 100%;
+ display: block;
+ height: 100%;
}
app-button-bar {
- pointer-events: none;
- position: absolute;
- right: 0;
- top: 0;
- z-index: 2;
- transition: right ease-out 0.25s;
+ pointer-events: none;
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: 2;
+ transition: right ease-out 0.25s;
}
diff --git a/src/app/modules/blockly-editor/blockly-editor.page.spec.ts b/src/app/modules/blockly-editor/blockly-editor.page.spec.ts
index 2c98e2f5..44ea5644 100644
--- a/src/app/modules/blockly-editor/blockly-editor.page.spec.ts
+++ b/src/app/modules/blockly-editor/blockly-editor.page.spec.ts
@@ -1,25 +1,24 @@
-import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";
-import { BlocklyEditorPage } from './blockly-editor.page';
+import { BlocklyEditorPage } from "./blockly-editor.page";
-describe('BlocklyEditorPage', () => {
- let component: BlocklyEditorPage;
- let fixture: ComponentFixture;
+describe("BlocklyEditorPage", () => {
+ let component: BlocklyEditorPage;
+ let fixture: ComponentFixture;
- beforeEach(waitForAsync(() => {
- TestBed.configureTestingModule({
- declarations: [ BlocklyEditorPage ]
- })
- .compileComponents();
- }));
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [BlocklyEditorPage],
+ }).compileComponents();
+ }));
- beforeEach(() => {
- fixture = TestBed.createComponent(BlocklyEditorPage);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BlocklyEditorPage);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
- it('should create', () => {
- expect(component).toBeTruthy();
- });
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
});
diff --git a/src/app/modules/blockly-editor/blockly-editor.page.ts b/src/app/modules/blockly-editor/blockly-editor.page.ts
index c44767f3..d2fda5f0 100644
--- a/src/app/modules/blockly-editor/blockly-editor.page.ts
+++ b/src/app/modules/blockly-editor/blockly-editor.page.ts
@@ -1,30 +1,27 @@
-import {Component} from '@angular/core';
-import {BlocklyEditorState} from 'src/app/state/blockly-editor.state';
-import {CommonModule} from "@angular/common";
-import {SharedModule} from "../shared/shared.module";
-import {BlocklyEditorModule} from "./blockly-editor.module";
-import {WorkspaceService} from "../../services/workspace.service";
+import { Component } from "@angular/core";
+import { BlocklyEditorState } from "src/app/state/blockly-editor.state";
+import { CommonModule } from "@angular/common";
+import { SharedModule } from "../shared/shared.module";
+import { BlocklyEditorModule } from "./blockly-editor.module";
+import { WorkspaceService } from "../../services/workspace.service";
@Component({
standalone: true,
- selector: 'app-blockly-editor',
- templateUrl: './blockly-editor.page.html',
- styleUrls: ['./blockly-editor.page.scss'],
- imports: [
- CommonModule,
- SharedModule,
- BlocklyEditorModule
- ],
+ selector: "app-blockly-editor",
+ templateUrl: "./blockly-editor.page.html",
+ styleUrls: ["./blockly-editor.page.scss"],
+ imports: [CommonModule, SharedModule, BlocklyEditorModule],
})
-
export class BlocklyEditorPage {
constructor(
public blocklyState: BlocklyEditorState,
private blocklyEditorState: BlocklyEditorState,
- private workspaceService: WorkspaceService
+ private workspaceService: WorkspaceService,
) {
window.addEventListener("beforeunload", async (event) => {
- this.workspaceService.saveWorkspaceTemp(this.blocklyEditorState.workspaceJSON);
+ this.workspaceService.saveWorkspaceTemp(
+ this.blocklyEditorState.workspaceJSON,
+ );
});
}
}
diff --git a/src/app/modules/blockly-editor/components/code-view/code-view.component.scss b/src/app/modules/blockly-editor/components/code-view/code-view.component.scss
index c69eb81f..2b52e80d 100644
--- a/src/app/modules/blockly-editor/components/code-view/code-view.component.scss
+++ b/src/app/modules/blockly-editor/components/code-view/code-view.component.scss
@@ -1,6 +1,6 @@
.code-view {
- width: 100%;
- height: 100%;
- margin: 0;
- overflow-x: scroll;
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ overflow-x: scroll;
}
diff --git a/src/app/modules/blockly-editor/components/code-view/code-view.component.spec.ts b/src/app/modules/blockly-editor/components/code-view/code-view.component.spec.ts
index edfe7e3b..73adac73 100644
--- a/src/app/modules/blockly-editor/components/code-view/code-view.component.spec.ts
+++ b/src/app/modules/blockly-editor/components/code-view/code-view.component.spec.ts
@@ -1,25 +1,24 @@
-import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";
-import { CodeViewComponent } from './code-view.component';
+import { CodeViewComponent } from "./code-view.component";
-describe('CodeViewComponent', () => {
- let component: CodeViewComponent;
- let fixture: ComponentFixture;
+describe("CodeViewComponent", () => {
+ let component: CodeViewComponent;
+ let fixture: ComponentFixture;
- beforeEach(waitForAsync(() => {
- TestBed.configureTestingModule({
- declarations: [ CodeViewComponent ]
- })
- .compileComponents();
- }));
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [CodeViewComponent],
+ }).compileComponents();
+ }));
- beforeEach(() => {
- fixture = TestBed.createComponent(CodeViewComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CodeViewComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
- it('should create', () => {
- expect(component).toBeTruthy();
- });
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
});
diff --git a/src/app/modules/blockly-editor/components/code-view/code-view.component.ts b/src/app/modules/blockly-editor/components/code-view/code-view.component.ts
index d568a89a..4fac14fc 100644
--- a/src/app/modules/blockly-editor/components/code-view/code-view.component.ts
+++ b/src/app/modules/blockly-editor/components/code-view/code-view.component.ts
@@ -1,18 +1,17 @@
-import {Component} from '@angular/core';
-import {CodeEditorState} from "../../../../state/code-editor.state";
+import { Component } from "@angular/core";
+import { CodeEditorState } from "../../../../state/code-editor.state";
@Component({
- selector: 'app-code-view',
- templateUrl: './code-view.component.html',
- styleUrls: ['./code-view.component.scss']
+ selector: "app-code-view",
+ templateUrl: "./code-view.component.html",
+ styleUrls: ["./code-view.component.scss"],
})
export class CodeViewComponent {
editorOptions = {
- language: 'cpp',
+ language: "cpp",
readOnly: true,
- automaticLayout: true
- }
+ automaticLayout: true,
+ };
- constructor(public codeEditor: CodeEditorState) {
- }
+ constructor(public codeEditor: CodeEditorState) {}
}
diff --git a/src/app/modules/blockly-editor/components/leaphy-blockly/backpack.plugin.ts b/src/app/modules/blockly-editor/components/leaphy-blockly/backpack.plugin.ts
index 968bbb57..dc94ae38 100644
--- a/src/app/modules/blockly-editor/components/leaphy-blockly/backpack.plugin.ts
+++ b/src/app/modules/blockly-editor/components/leaphy-blockly/backpack.plugin.ts
@@ -1,4 +1,4 @@
-import { Backpack as BaseBackpack } from '@blockly/workspace-backpack';
+import { Backpack as BaseBackpack } from "@blockly/workspace-backpack";
import Blockly from "blockly/core";
export class Backpack extends BaseBackpack {
@@ -16,11 +16,12 @@ export class Backpack extends BaseBackpack {
rtl: this.workspace_.RTL,
oneBasedIndex: this.workspace_.options.oneBasedIndex,
renderer: this.workspace_.options.renderer,
- rendererOverrides: this.workspace_.options.rendererOverrides || undefined,
+ rendererOverrides:
+ this.workspace_.options.rendererOverrides || undefined,
move: {
scrollbars: true,
},
- toolboxPosition: 'left'
+ toolboxPosition: "left",
});
// Create flyout.
@@ -37,7 +38,7 @@ export class Backpack extends BaseBackpack {
this.flyout_.init(this.workspace_);
}
override addBlock(block: Blockly.Block) {
- if (block.type === 'leaphy_start') {
+ if (block.type === "leaphy_start") {
this.addBlocks(block.getChildren(false));
block.getChildren(false).forEach((child) => {
setTimeout(() => child.dispose(undefined), 0);
@@ -51,12 +52,17 @@ export class Backpack extends BaseBackpack {
setTimeout(() => block.dispose(undefined), 0);
}
- override position(metrics: Blockly.MetricsManager.UiMetrics, savedPositions: Blockly.utils.Rect[]) {
+ override position(
+ metrics: Blockly.MetricsManager.UiMetrics,
+ savedPositions: Blockly.utils.Rect[],
+ ) {
const toolbox = this.workspace_.getToolbox();
this.left_ =
metrics.absoluteMetrics.left +
- (!toolbox.getFlyout().isVisible() ? -toolbox.getFlyout().getWidth() : 0) +
+ (!toolbox.getFlyout().isVisible()
+ ? -toolbox.getFlyout().getWidth()
+ : 0) +
this.MARGIN_HORIZONTAL_;
this.top_ =
@@ -68,10 +74,9 @@ export class Backpack extends BaseBackpack {
if (this.svgGroup_) {
this.svgGroup_.setAttribute(
- 'transform',
+ "transform",
`translate(${this.left_},${this.top_})`,
);
}
}
}
-
diff --git a/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.html b/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.html
index a200bfaa..b7a8799c 100644
--- a/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.html
+++ b/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.html
@@ -1,6 +1,11 @@
-
- @if (background) {
-
- }
+
+ @if (background) {
+
+ }
diff --git a/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.scss b/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.scss
index 991ebdf6..b472857e 100644
--- a/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.scss
+++ b/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.scss
@@ -1,4 +1,5 @@
-.workspace-container, #blockly-container {
+.workspace-container,
+#blockly-container {
top: 0px;
width: 100%;
height: 100%;
diff --git a/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.spec.ts b/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.spec.ts
index 87dbcf5f..18db7c58 100644
--- a/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.spec.ts
+++ b/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.spec.ts
@@ -1,25 +1,24 @@
-import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
+import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";
-import { LeaphyBlocklyComponent } from './leaphy-blockly.component';
+import { LeaphyBlocklyComponent } from "./leaphy-blockly.component";
-describe('LeaphyBlocklyComponent', () => {
- let component: LeaphyBlocklyComponent;
- let fixture: ComponentFixture;
+describe("LeaphyBlocklyComponent", () => {
+ let component: LeaphyBlocklyComponent;
+ let fixture: ComponentFixture;
- beforeEach(waitForAsync(() => {
- TestBed.configureTestingModule({
- declarations: [ LeaphyBlocklyComponent ]
- })
- .compileComponents();
- }));
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [LeaphyBlocklyComponent],
+ }).compileComponents();
+ }));
- beforeEach(() => {
- fixture = TestBed.createComponent(LeaphyBlocklyComponent);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
+ beforeEach(() => {
+ fixture = TestBed.createComponent(LeaphyBlocklyComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
- it('should create', () => {
- expect(component).toBeTruthy();
- });
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
});
diff --git a/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.ts b/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.ts
index 21217887..986e962a 100644
--- a/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.ts
+++ b/src/app/modules/blockly-editor/components/leaphy-blockly/leaphy-blockly.component.ts
@@ -1,87 +1,92 @@
-import {
- Component,
- ViewChild,
- ElementRef,
- AfterViewInit,
-} from '@angular/core';
-import { BlocklyEditorState } from 'src/app/state/blockly-editor.state';
-import {Backpack} from "./backpack.plugin";
-import Blockly from 'blockly/core';
-import {BackpackChange} from "@blockly/workspace-backpack/dist";
-import {AppState} from "src/app/state/app.state";
-import {WorkspaceSvg} from "blockly";
+import { Component, ViewChild, ElementRef, AfterViewInit } from "@angular/core";
+import { BlocklyEditorState } from "src/app/state/blockly-editor.state";
+import { Backpack } from "./backpack.plugin";
+import Blockly from "blockly/core";
+import { BackpackChange } from "@blockly/workspace-backpack/dist";
+import { AppState } from "src/app/state/app.state";
+import { WorkspaceSvg } from "blockly";
type Background = {
- src: string,
- x: string,
-}
+ src: string;
+ x: string;
+};
@Component({
- selector: 'app-leaphy-blockly',
- templateUrl: './leaphy-blockly.component.html',
- styleUrls: ['./leaphy-blockly.component.scss']
+ selector: "app-leaphy-blockly",
+ templateUrl: "./leaphy-blockly.component.html",
+ styleUrls: ["./leaphy-blockly.component.scss"],
})
export class LeaphyBlocklyComponent implements AfterViewInit {
+ @ViewChild("blockContent") blockContent: ElementRef;
- @ViewChild('blockContent') blockContent: ElementRef;
-
- public background: Background
- private workspace: WorkspaceSvg
+ public background: Background;
+ private workspace: WorkspaceSvg;
constructor(
public appState: AppState,
public blocklyState: BlocklyEditorState,
) {
- appState.selectedRobotType$.subscribe(robot => {
- if (!robot?.background) return this.background = null
+ appState.selectedRobotType$.subscribe((robot) => {
+ if (!robot?.background) return (this.background = null);
if (this.background) {
- this.background.src = robot.background
+ this.background.src = robot.background;
} else {
this.background = {
src: robot.background,
- x: '50%'
- }
+ x: "50%",
+ };
}
- })
+ });
- window.addEventListener('resize', this.updateSizing.bind(this))
+ window.addEventListener("resize", this.updateSizing.bind(this));
}
updateSizing() {
- if (!this.background || !this.workspace) return
+ if (!this.background || !this.workspace) return;
const toolbox = this.workspace.getToolbox();
- this.background.x = `${window.innerWidth / 2 + (toolbox.getFlyout().isVisible() ? toolbox.getFlyout().getWidth() : 0)/2 + 40}px`
+ this.background.x = `${window.innerWidth / 2 + (toolbox.getFlyout().isVisible() ? toolbox.getFlyout().getWidth() : 0) / 2 + 40}px`;
}
ngAfterViewInit() {
this.blocklyState.blocklyElement = this.blockContent.nativeElement;
- this.blocklyState.workspace$.subscribe(workspace => {
- this.workspace = workspace
+ this.blocklyState.workspace$.subscribe((workspace) => {
+ this.workspace = workspace;
workspace.addChangeListener((event: any) => {
// @ts-ignore
- if (!(event.type === "toolbox_item_select")) {return}
+ if (!(event.type === "toolbox_item_select")) {
+ return;
+ }
workspace.resize();
- })
+ });
- workspace.addChangeListener(this.updateSizing.bind(this))
+ workspace.addChangeListener(this.updateSizing.bind(this));
if (!workspace.backpack) {
const backpack = new Backpack(workspace);
workspace.backpack = backpack;
- Blockly.registry.unregister(Blockly.registry.Type.SERIALIZER, "backpack")
-
-
- backpack.setContents(JSON.parse(localStorage.getItem('backpack')) || []);
- workspace.addChangeListener((event: Blockly.Events.Abstract) => {
- if (!(event instanceof BackpackChange)) return;
-
- localStorage.setItem('backpack', JSON.stringify(backpack.getContents()));
- });
+ Blockly.registry.unregister(
+ Blockly.registry.Type.SERIALIZER,
+ "backpack",
+ );
+
+ backpack.setContents(
+ JSON.parse(localStorage.getItem("backpack")) || [],
+ );
+ workspace.addChangeListener(
+ (event: Blockly.Events.Abstract) => {
+ if (!(event instanceof BackpackChange)) return;
+
+ localStorage.setItem(
+ "backpack",
+ JSON.stringify(backpack.getContents()),
+ );
+ },
+ );
backpack.init();
}
- })
+ });
}
}
diff --git a/src/app/modules/code-editor-cpp/code-editor-cpp.page.scss b/src/app/modules/code-editor-cpp/code-editor-cpp.page.scss
index e06ddb52..d6ab890e 100644
--- a/src/app/modules/code-editor-cpp/code-editor-cpp.page.scss
+++ b/src/app/modules/code-editor-cpp/code-editor-cpp.page.scss
@@ -4,27 +4,27 @@
}
#container {
- display: flex;
- flex-direction: row;
- align-items: stretch;
- height: calc(100% - 64px);
- width: 100%;
- overflow: hidden;
+ display: flex;
+ flex-direction: row;
+ align-items: stretch;
+ height: calc(100% - 64px);
+ width: 100%;
+ overflow: hidden;
}
.sidenav-container {
- flex: 1 1 auto;
- background: #eee;
+ flex: 1 1 auto;
+ background: #eee;
}
#sidenav {
- min-width: 20%;
+ min-width: 20%;
}
app-button-bar {
- pointer-events: none;
- position: absolute;
- right: 0;
- top: 0;
- z-index: 5;
+ pointer-events: none;
+ position: absolute;
+ right: 0;
+ top: 0;
+ z-index: 5;
}
diff --git a/src/app/modules/code-editor-cpp/code-editor-cpp.page.spec.ts b/src/app/modules/code-editor-cpp/code-editor-cpp.page.spec.ts
index 6204a897..8a16ad8c 100644
--- a/src/app/modules/code-editor-cpp/code-editor-cpp.page.spec.ts
+++ b/src/app/modules/code-editor-cpp/code-editor-cpp.page.spec.ts
@@ -1,25 +1,24 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ComponentFixture, TestBed } from "@angular/core/testing";
-import { CodeEditorCppPage } from './code-editor-cpp.page';
+import { CodeEditorCppPage } from "./code-editor-cpp.page";
-describe('CodeEditorPage', () => {
- let component: CodeEditorCppPage;
- let fixture: ComponentFixture;
+describe("CodeEditorPage", () => {
+ let component: CodeEditorCppPage;
+ let fixture: ComponentFixture;
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ CodeEditorCppPage ]
- })
- .compileComponents();
- });
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [CodeEditorCppPage],
+ }).compileComponents();
+ });
- beforeEach(() => {
- fixture = TestBed.createComponent(CodeEditorCppPage);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CodeEditorCppPage);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
- it('should create', () => {
- expect(component).toBeTruthy();
- });
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
});
diff --git a/src/app/modules/code-editor-cpp/code-editor-cpp.page.ts b/src/app/modules/code-editor-cpp/code-editor-cpp.page.ts
index 82f4e0ce..8702b8dd 100644
--- a/src/app/modules/code-editor-cpp/code-editor-cpp.page.ts
+++ b/src/app/modules/code-editor-cpp/code-editor-cpp.page.ts
@@ -1,38 +1,34 @@
-import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
-import {CodeEditorState} from 'src/app/state/code-editor.state';
-import {CommonModule} from "@angular/common";
-import {SharedModule} from "../shared/shared.module";
-import {CoreModule} from "../core/core.module";
-import {WorkspaceService} from "../../services/workspace.service";
-import {MonacoEditorModule} from "ngx-monaco-editor-v2";
-
+import { AfterViewInit, Component, ElementRef, ViewChild } from "@angular/core";
+import { CodeEditorState } from "src/app/state/code-editor.state";
+import { CommonModule } from "@angular/common";
+import { SharedModule } from "../shared/shared.module";
+import { CoreModule } from "../core/core.module";
+import { WorkspaceService } from "../../services/workspace.service";
+import { MonacoEditorModule } from "ngx-monaco-editor-v2";
@Component({
standalone: true,
- selector: 'app-code-editor-cpp',
- templateUrl: './code-editor-cpp.page.html',
- styleUrls: ['./code-editor-cpp.page.scss'],
- imports: [
- CommonModule,
- SharedModule,
- CoreModule,
- MonacoEditorModule
- ]
+ selector: "app-code-editor-cpp",
+ templateUrl: "./code-editor-cpp.page.html",
+ styleUrls: ["./code-editor-cpp.page.scss"],
+ imports: [CommonModule, SharedModule, CoreModule, MonacoEditorModule],
})
export class CodeEditorCppPage implements AfterViewInit {
editorOptions = {
- language: 'cpp',
- automaticLayout: true
- }
+ language: "cpp",
+ automaticLayout: true,
+ };
constructor(
public codeEditorState: CodeEditorState,
- private workspaceService: WorkspaceService
+ private workspaceService: WorkspaceService,
) {}
ngAfterViewInit(): void {
window.addEventListener("beforeunload", async () => {
- await this.workspaceService.saveWorkspaceTemp(this.codeEditorState.code);
+ await this.workspaceService.saveWorkspaceTemp(
+ this.codeEditorState.code,
+ );
});
}
}
diff --git a/src/app/modules/code-editor-python/code-editor-python.page.scss b/src/app/modules/code-editor-python/code-editor-python.page.scss
index f77a4adb..ee901bd8 100644
--- a/src/app/modules/code-editor-python/code-editor-python.page.scss
+++ b/src/app/modules/code-editor-python/code-editor-python.page.scss
@@ -1,6 +1,6 @@
.monaco-editor {
width: 100%;
- height: 80%
+ height: 80%;
}
#container {
diff --git a/src/app/modules/code-editor-python/code-editor-python.page.spec.ts b/src/app/modules/code-editor-python/code-editor-python.page.spec.ts
index 927af20a..d72f0e01 100644
--- a/src/app/modules/code-editor-python/code-editor-python.page.spec.ts
+++ b/src/app/modules/code-editor-python/code-editor-python.page.spec.ts
@@ -1,25 +1,24 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { ComponentFixture, TestBed } from "@angular/core/testing";
-import { CodeEditorPythonPage } from './code-editor-python.page';
+import { CodeEditorPythonPage } from "./code-editor-python.page";
-describe('CodeEditorPythonPage', () => {
- let component: CodeEditorPythonPage;
- let fixture: ComponentFixture;
+describe("CodeEditorPythonPage", () => {
+ let component: CodeEditorPythonPage;
+ let fixture: ComponentFixture;
- beforeEach(async () => {
- await TestBed.configureTestingModule({
- declarations: [ CodeEditorPythonPage ]
- })
- .compileComponents();
- });
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [CodeEditorPythonPage],
+ }).compileComponents();
+ });
- beforeEach(() => {
- fixture = TestBed.createComponent(CodeEditorPythonPage);
- component = fixture.componentInstance;
- fixture.detectChanges();
- });
+ beforeEach(() => {
+ fixture = TestBed.createComponent(CodeEditorPythonPage);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
- it('should create', () => {
- expect(component).toBeTruthy();
- });
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
});
diff --git a/src/app/modules/code-editor-python/code-editor-python.page.ts b/src/app/modules/code-editor-python/code-editor-python.page.ts
index f0b8e847..45a2fd92 100644
--- a/src/app/modules/code-editor-python/code-editor-python.page.ts
+++ b/src/app/modules/code-editor-python/code-editor-python.page.ts
@@ -1,38 +1,34 @@
-import {AfterViewInit, Component, ElementRef, ViewChild} from '@angular/core';
-import {CodeEditorState} from 'src/app/state/code-editor.state';
-import {CommonModule} from "@angular/common";
-import {SharedModule} from "../shared/shared.module";
-import {CoreModule} from "../core/core.module";
-import {WorkspaceService} from "../../services/workspace.service";
-import {MonacoEditorModule} from "ngx-monaco-editor-v2";
-
+import { AfterViewInit, Component, ElementRef, ViewChild } from "@angular/core";
+import { CodeEditorState } from "src/app/state/code-editor.state";
+import { CommonModule } from "@angular/common";
+import { SharedModule } from "../shared/shared.module";
+import { CoreModule } from "../core/core.module";
+import { WorkspaceService } from "../../services/workspace.service";
+import { MonacoEditorModule } from "ngx-monaco-editor-v2";
@Component({
- selector: 'app-code-editor-python',
+ selector: "app-code-editor-python",
standalone: true,
- templateUrl: './code-editor-python.page.html',
- styleUrls: ['./code-editor-python.page.scss'],
- imports: [
- CommonModule,
- SharedModule,
- CoreModule,
- MonacoEditorModule
- ]
+ templateUrl: "./code-editor-python.page.html",
+ styleUrls: ["./code-editor-python.page.scss"],
+ imports: [CommonModule, SharedModule, CoreModule, MonacoEditorModule],
})
export class CodeEditorPythonPage implements AfterViewInit {
editorOptions = {
- language: 'python',
- automaticLayout: true
- }
+ language: "python",
+ automaticLayout: true,
+ };
constructor(
public codeEditorState: CodeEditorState,
- private workspaceService: WorkspaceService
+ private workspaceService: WorkspaceService,
) {}
ngAfterViewInit(): void {
window.addEventListener("beforeunload", async () => {
- await this.workspaceService.saveWorkspaceTemp(this.codeEditorState.code);
- })
+ await this.workspaceService.saveWorkspaceTemp(
+ this.codeEditorState.code,
+ );
+ });
}
}
diff --git a/src/app/modules/components/header/header.component.html b/src/app/modules/components/header/header.component.html
index d4a6cc8b..49eef160 100644
--- a/src/app/modules/components/header/header.component.html
+++ b/src/app/modules/components/header/header.component.html
@@ -1,9 +1,16 @@
-
+