summaryrefslogtreecommitdiff
path: root/blocks
diff options
context:
space:
mode:
Diffstat (limited to 'blocks')
-rw-r--r--blocks/.dockerignore5
-rw-r--r--blocks/Dockerfile5
-rw-r--r--blocks/Dockerfile.patch10
-rw-r--r--blocks/authAPI/emails.py16
-rw-r--r--blocks/authAPI/views.py7
-rw-r--r--blocks/blocks/settings.py26
-rw-r--r--blocks/blocks/xcosblocks/urls.py4
-rw-r--r--blocks/blocks/xcosblocks/views.py6
-rw-r--r--blocks/eda-frontend/.babelrc.json3
-rw-r--r--blocks/eda-frontend/package-lock.json291
-rw-r--r--blocks/eda-frontend/package.json10
-rw-r--r--blocks/eda-frontend/public/css/common.css192
-rw-r--r--blocks/eda-frontend/src/App.js29
-rw-r--r--blocks/eda-frontend/src/components/Dashboard/DashboardSidebar.js11
-rw-r--r--blocks/eda-frontend/src/components/Dashboard/ProgressPanel.js12
-rw-r--r--blocks/eda-frontend/src/components/Dashboard/SchematicsList.js12
-rw-r--r--blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js29
-rw-r--r--blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js6
-rw-r--r--blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js103
-rw-r--r--blocks/eda-frontend/src/pages/Login.js17
-rw-r--r--blocks/eda-frontend/src/redux/authSlice.js36
-rw-r--r--blocks/eda-frontend/src/redux/dashboardSlice.js5
-rw-r--r--blocks/eda-frontend/src/utils/GalleryUtils.js11
-rwxr-xr-xblocks/init.sh6
-rw-r--r--blocks/simulationAPI/helpers/ngspice_helper.py26
-rw-r--r--blocks/simulationAPI/helpers/scilab_manager.py3
-rw-r--r--blocks/xcos2xml/blocks/ConstantVoltage.xsl4
-rw-r--r--blocks/xcos2xml/blocks/Resistor.xsl3
-rw-r--r--blocks/xcos2xml/blocks/SUPER_f.xsl8
-rw-r--r--blocks/xcos2xml/blocks/TEXT_f.xsl7
-rw-r--r--blocks/xcos2xml/head.xsl211
31 files changed, 569 insertions, 545 deletions
diff --git a/blocks/.dockerignore b/blocks/.dockerignore
index 5e6b38b0..6de483dd 100644
--- a/blocks/.dockerignore
+++ b/blocks/.dockerignore
@@ -9,8 +9,11 @@ env*
*.sqlite3
*.swp
.DS_Store
-**/.env
+.env
**/.env.*
+**/.git*
+**/.nvmrc
+**/.vscode
**/build
**/node_modules
tags
diff --git a/blocks/Dockerfile b/blocks/Dockerfile
index f8bfc6ae..f07ce843 100644
--- a/blocks/Dockerfile
+++ b/blocks/Dockerfile
@@ -105,7 +105,7 @@ FROM base AS build-xcos
RUN apt-get update -qq && \
apt-get install -qq --no-install-recommends gawk python3-pip python3-venv wget xz-utils
-ARG NODE_VERSION=v20.19.0
+ARG NODE_VERSION=v20.19.3
ARG NODE=node-${NODE_VERSION}-linux-x64
WORKDIR ${HOME}
RUN wget -q --no-hsts https://nodejs.org/download/release/${NODE_VERSION}/${NODE}.tar.xz && \
@@ -121,9 +121,6 @@ COPY . .
# Configure venv and sqlite3
RUN ./install.sh
-# For localhost only
-RUN echo 'WDS_SOCKET_PORT=80' > eda-frontend/.env.local
-
# Cleanup
RUN apt-get autoremove -qq --purge gawk python3-pip python3-venv wget xz-utils
RUN apt-get clean -qq
diff --git a/blocks/Dockerfile.patch b/blocks/Dockerfile.patch
index 0a94dd1c..069a62cc 100644
--- a/blocks/Dockerfile.patch
+++ b/blocks/Dockerfile.patch
@@ -1,5 +1,5 @@
---- Dockerfile 2025-07-04 16:16:28.040919228 +0530
-+++ Dockerfile.1 2025-07-04 16:19:16.930142599 +0530
+--- Dockerfile 2025-07-08 18:20:34.818712259 +0530
++++ Dockerfile.1 2025-07-08 18:21:40.192702872 +0530
@@ -119,7 +119,7 @@
COPY . .
@@ -7,9 +7,9 @@
-RUN ./install.sh
+RUN ./install.sh prod
- # For localhost only
- RUN echo 'WDS_SOCKET_PORT=80' > eda-frontend/.env.local
-@@ -173,4 +173,4 @@
+ # Cleanup
+ RUN apt-get autoremove -qq --purge gawk python3-pip python3-venv wget xz-utils
+@@ -170,4 +170,4 @@
WORKDIR ${XCOS_DIR}
diff --git a/blocks/authAPI/emails.py b/blocks/authAPI/emails.py
new file mode 100644
index 00000000..2f112c74
--- /dev/null
+++ b/blocks/authAPI/emails.py
@@ -0,0 +1,16 @@
+from djoser import email
+from django.conf import settings
+
+
+class CustomActivationEmail(email.ActivationEmail):
+ def get_context_data(self):
+ context = super().get_context_data()
+ context['protocol'] = settings.DEFAULT_PROTOCOL
+ return context
+
+
+class CustomPasswordResetEmail(email.PasswordResetEmail):
+ def get_context_data(self):
+ context = super().get_context_data()
+ context['protocol'] = settings.DEFAULT_PROTOCOL
+ return context
diff --git a/blocks/authAPI/views.py b/blocks/authAPI/views.py
index e1cc173b..8afd799a 100644
--- a/blocks/authAPI/views.py
+++ b/blocks/authAPI/views.py
@@ -10,7 +10,6 @@ from django.http import HttpResponseNotFound
from djoser import utils
from djoser.serializers import TokenSerializer
from authAPI.serializers import TokenCreateSerializer
-from blocks.settings import DOMAIN
Token = djoser_settings.TOKEN_MODEL
@@ -26,8 +25,7 @@ def activate_user(request, uid, token):
Link to this route is sent via email to user for verification
"""
- protocol = 'https://' if request.is_secure() else 'http://'
- web_url = protocol + request.get_host() + '/api/auth/users/activation/' # URL comes from Djoser library
+ web_url = settings.POST_ACTIVATE_REDIRECT_URL + 'api/auth/users/activation/' # URL comes from Djoser library
return render(request, 'activate_user.html',
{'uid': uid,
'token': token,
@@ -50,8 +48,7 @@ def get_social_user(email, request, callback, service):
user.save()
token, created = Token.objects.get_or_create(user=user)
- protocol = 'https://' if request.is_secure() else 'http://'
- web_url = protocol + DOMAIN + '/#/dashboard'
+ web_url = settings.POST_ACTIVATE_REDIRECT_URL + '#/dashboard'
return render(request, callback,
{'token': token,
diff --git a/blocks/blocks/settings.py b/blocks/blocks/settings.py
index 0f95850b..e62c1fda 100644
--- a/blocks/blocks/settings.py
+++ b/blocks/blocks/settings.py
@@ -13,6 +13,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
import os
from pathlib import Path
from dotenv import load_dotenv
+from urllib.parse import urlparse
# Loading the .env file
load_dotenv()
@@ -136,12 +137,14 @@ SESSION_COOKIE_SAMESITE = 'Lax'
# use this for console emails
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
-# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
-# EMAIL_HOST = os.environ.get('EMAIL_HOST', 'smtp.gmail.com')
-# EMAIL_PORT = os.environ.get('EMAIL_PORT', 587)
-# EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER', 'email@gmail.com')
-# EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', 'gmailpassword')
-# EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', True)
+EMAIL_HOST = os.environ.get('EMAIL_HOST', '')
+EMAIL_PORT = int(os.environ.get('EMAIL_PORT', '587'))
+EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER', '')
+EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD', '')
+EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', 'true').lower() == 'true'
+DEFAULT_FROM_EMAIL = os.environ.get('FROM_EMAIL', 'webmaster@localhost')
+if EMAIL_HOST:
+ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = os.environ.get('SOCIAL_AUTH_GOOGLE_OAUTH2_KEY', '')
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ.get('SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET', '')
@@ -153,7 +156,9 @@ GITHUB_OAUTH_REDIRECT_URI = os.environ.get('GITHUB_OAUTH_REDIRECT_URI',
'http://localhost/api/auth/github-callback')
POST_ACTIVATE_REDIRECT_URL = os.environ.get('POST_ACTIVATE_REDIRECT_URL',
'http://localhost/')
-DOMAIN = os.environ.get('EMAIL_DOMAIN', 'localhost')
+parsed_url = urlparse(POST_ACTIVATE_REDIRECT_URL)
+DEFAULT_PROTOCOL = parsed_url.scheme or 'http'
+DOMAIN = parsed_url.netloc or 'localhost'
SITE_NAME = os.environ.get('EMAIL_SITE_NAME', 'Xcos')
DJOSER = {
@@ -178,6 +183,10 @@ DJOSER = {
'user_delete': 'djoser.serializers.UserDeleteSerializer',
'token_create': 'authAPI.serializers.TokenCreateSerializer',
},
+ 'EMAIL': {
+ 'activation': 'authAPI.emails.CustomActivationEmail',
+ 'password_reset': 'authAPI.emails.CustomPasswordResetEmail',
+ }
}
REST_FRAMEWORK = {
@@ -210,6 +219,9 @@ TRUSTED_ORIGINS = os.environ.get('TRUSTED_ORIGINS', 'http://localhost')
CORS_ALLOWED_ORIGINS = [i for i in ALLOWED_ORIGINS.split(',') if i != '']
CSRF_TRUSTED_ORIGINS = [i for i in TRUSTED_ORIGINS.split(',') if i != '']
CORS_ALLOW_CREDENTIALS = True
+CSRF_COOKIE_HTTPONLY = os.environ.get('COOKIE_HTTPONLY', 'false').lower() == 'true'
+CSRF_COOKIE_SAMESITE = os.environ.get('COOKIE_SAMESITE', 'Lax')
+CSRF_COOKIE_SECURE = os.environ.get('COOKIE_SECURE', 'false').lower() == 'true'
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/
diff --git a/blocks/blocks/xcosblocks/urls.py b/blocks/blocks/xcosblocks/urls.py
index a17259d7..6205e437 100644
--- a/blocks/blocks/xcosblocks/urls.py
+++ b/blocks/blocks/xcosblocks/urls.py
@@ -1,7 +1,7 @@
from django.urls import path
from rest_framework.routers import SimpleRouter
-from .views import CategoryViewSet, \
+from .views import init_csrf, CategoryViewSet, \
NewBlockViewSet, NewBlockParameterViewSet, \
get_block_images, set_block_parameter
@@ -12,7 +12,7 @@ router.register(r'newblocks', NewBlockViewSet)
router.register(r'newblockparameters', NewBlockParameterViewSet)
urlpatterns = router.urls + [
+ path(r'init', init_csrf, name='init-csrf'),
path(r'block_images', get_block_images),
-
path(r'setblockparameter', set_block_parameter),
]
diff --git a/blocks/blocks/xcosblocks/views.py b/blocks/blocks/xcosblocks/views.py
index 64bc5ff7..2754f915 100644
--- a/blocks/blocks/xcosblocks/views.py
+++ b/blocks/blocks/xcosblocks/views.py
@@ -1,4 +1,5 @@
from django.http import JsonResponse
+from django.views.decorators.csrf import ensure_csrf_cookie
from django_filters import FilterSet
from django_filters.rest_framework import DjangoFilterBackend
import io
@@ -13,6 +14,11 @@ from .serializers import CategorySerializer, \
NewBlockSerializer, NewBlockParameterSerializer, NewBlockPortSerializer
+@ensure_csrf_cookie
+def init_csrf(request):
+ return JsonResponse({"message": "CSRF cookie set"})
+
+
class CategoryFilterSet(FilterSet):
class Meta:
model = Category
diff --git a/blocks/eda-frontend/.babelrc.json b/blocks/eda-frontend/.babelrc.json
deleted file mode 100644
index 7dd5e9df..00000000
--- a/blocks/eda-frontend/.babelrc.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "presets": ["@babel/preset-react"]
-}
diff --git a/blocks/eda-frontend/package-lock.json b/blocks/eda-frontend/package-lock.json
index 3bad5db2..778e966a 100644
--- a/blocks/eda-frontend/package-lock.json
+++ b/blocks/eda-frontend/package-lock.json
@@ -19,7 +19,7 @@
"highcharts-react-official": "^3.2.2",
"mxgraph": "^4.2.2",
"prop-types": "^15.8.1",
- "query-string": "^9.2.1",
+ "query-string": "^9.2.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-loader-spinner": "^6.1.6",
@@ -30,14 +30,14 @@
"xml-beautifier": "^0.5.0"
},
"devDependencies": {
- "@babel/eslint-parser": "^7.27.5",
- "eslint": "^9.30.0",
+ "@babel/eslint-parser": "^7.28.0",
+ "eslint": "^9.31.0",
"eslint-plugin-import": "^2.32.0",
- "eslint-plugin-n": "^17.20.0",
+ "eslint-plugin-n": "^17.21.0",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
- "globals": "^16.2.0",
+ "globals": "^16.3.0",
"react-dev-utils": "^12.0.1",
"react-scripts": "^5.0.1",
"source-map-explorer": "^2.5.2"
@@ -120,9 +120,9 @@
}
},
"node_modules/@babel/eslint-parser": {
- "version": "7.27.5",
- "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.27.5.tgz",
- "integrity": "sha512-HLkYQfRICudzcOtjGwkPvGc5nF1b4ljLZh1IRDj50lRZ718NAKVgQpIAUX8bfg6u/yuSKY3L7E0YzIV+OxrB8Q==",
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.28.0.tgz",
+ "integrity": "sha512-N4ntErOlKvcbTt01rr5wj3y55xnIdx1ymrfIr8C2WnM1Y9glFgWaGDEULJIazOX3XM9NRzhfJ6zZnQ1sBNWU+w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2400,9 +2400,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.30.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.0.tgz",
- "integrity": "sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww==",
+ "version": "9.31.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.31.0.tgz",
+ "integrity": "sha512-LOm5OVt7D4qiKCqoiPbA7LWmI+tbw1VbTUowBcUMgQSuM6poJufkFkYDcQpo5KfgD39TnNySV26QjOh7VFpSyw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -4540,42 +4540,6 @@
"integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
"dev": true
},
- "node_modules/@typescript-eslint/project-service": {
- "version": "8.33.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.1.tgz",
- "integrity": "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.33.1",
- "@typescript-eslint/types": "^8.33.1",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": {
- "version": "8.33.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.1.tgz",
- "integrity": "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
"node_modules/@typescript-eslint/scope-manager": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz",
@@ -4594,23 +4558,6 @@
"url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.33.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz",
- "integrity": "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
"node_modules/@typescript-eslint/type-utils": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz",
@@ -4734,161 +4681,6 @@
"node": ">=10"
}
},
- "node_modules/@typescript-eslint/utils": {
- "version": "8.33.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.1.tgz",
- "integrity": "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.7.0",
- "@typescript-eslint/scope-manager": "8.33.1",
- "@typescript-eslint/types": "8.33.1",
- "@typescript-eslint/typescript-estree": "8.33.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^8.57.0 || ^9.0.0",
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
- "version": "8.33.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz",
- "integrity": "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.33.1",
- "@typescript-eslint/visitor-keys": "8.33.1"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
- "version": "8.33.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.1.tgz",
- "integrity": "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.33.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz",
- "integrity": "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/project-service": "8.33.1",
- "@typescript-eslint/tsconfig-utils": "8.33.1",
- "@typescript-eslint/types": "8.33.1",
- "@typescript-eslint/visitor-keys": "8.33.1",
- "debug": "^4.3.4",
- "fast-glob": "^3.3.2",
- "is-glob": "^4.0.3",
- "minimatch": "^9.0.4",
- "semver": "^7.6.0",
- "ts-api-utils": "^2.1.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4 <5.9.0"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.33.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz",
- "integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@typescript-eslint/types": "8.33.1",
- "eslint-visitor-keys": "^4.2.0"
- },
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/eslint-visitor-keys": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz",
- "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==",
- "dev": true,
- "license": "Apache-2.0",
- "engines": {
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/@typescript-eslint/utils/node_modules/semver": {
- "version": "7.7.2",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
- "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
- "dev": true,
- "license": "ISC",
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/@typescript-eslint/visitor-keys": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz",
@@ -6356,9 +6148,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001699",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz",
- "integrity": "sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w==",
+ "version": "1.0.30001727",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz",
+ "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==",
"dev": true,
"funding": [
{
@@ -8190,9 +7982,9 @@
}
},
"node_modules/eslint": {
- "version": "9.30.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.0.tgz",
- "integrity": "sha512-iN/SiPxmQu6EVkf+m1qpBxzUhE12YqFLOSySuOyVLJLEF9nzTf+h/1AJYc1JWzCnktggeNrjvQGLngDzXirU6g==",
+ "version": "9.31.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.31.0.tgz",
+ "integrity": "sha512-QldCVh/ztyKJJZLr4jXNUByx3gR+TDYZCRXEktiZoUR3PGy4qCmSbkxcIle8GEwGpb5JBZazlaJ/CxLidXdEbQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8200,9 +7992,9 @@
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.21.0",
"@eslint/config-helpers": "^0.3.0",
- "@eslint/core": "^0.14.0",
+ "@eslint/core": "^0.15.0",
"@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.30.0",
+ "@eslint/js": "9.31.0",
"@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -8435,14 +8227,13 @@
}
},
"node_modules/eslint-plugin-n": {
- "version": "17.20.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.20.0.tgz",
- "integrity": "sha512-IRSoatgB/NQJZG5EeTbv/iAx1byOGdbbyhQrNvWdCfTnmPxUT0ao9/eGOeG7ljD8wJBsxwE8f6tES5Db0FRKEw==",
+ "version": "17.21.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.21.0.tgz",
+ "integrity": "sha512-1+iZ8We4ZlwVMtb/DcHG3y5/bZOdazIpa/4TySo22MLKdwrLcfrX0hbadnCvykSQCCmkAnWmIP8jZVb2AAq29A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.5.0",
- "@typescript-eslint/utils": "^8.26.1",
"enhanced-resolve": "^5.17.1",
"eslint-plugin-es-x": "^7.8.0",
"get-tsconfig": "^4.8.1",
@@ -8639,6 +8430,19 @@
"node": ">=10"
}
},
+ "node_modules/eslint/node_modules/@eslint/core": {
+ "version": "0.15.1",
+ "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz",
+ "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@types/json-schema": "^7.0.15"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ }
+ },
"node_modules/eslint/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -9797,9 +9601,9 @@
}
},
"node_modules/globals": {
- "version": "16.2.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
- "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz",
+ "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==",
"dev": true,
"license": "MIT",
"engines": {
@@ -16212,9 +16016,9 @@
}
},
"node_modules/query-string": {
- "version": "9.2.1",
- "resolved": "https://registry.npmjs.org/query-string/-/query-string-9.2.1.tgz",
- "integrity": "sha512-3jTGGLRzlhu/1ws2zlr4Q+GVMLCQTLFOj8CMX5x44cdZG9FQE07x2mQhaNxaKVPNmIDu0mvJ/cEwtY7Pim7hqA==",
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/query-string/-/query-string-9.2.2.tgz",
+ "integrity": "sha512-pDSIZJ9sFuOp6VnD+5IkakSVf+rICAuuU88Hcsr6AKL0QtxSIfVuKiVP2oahFI7tk3CRSexwV+Ya6MOoTxzg9g==",
"license": "MIT",
"dependencies": {
"decode-uri-component": "^0.4.1",
@@ -19572,19 +19376,6 @@
"integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==",
"dev": true
},
- "node_modules/ts-api-utils": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz",
- "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18.12"
- },
- "peerDependencies": {
- "typescript": ">=4.8.4"
- }
- },
"node_modules/ts-declaration-location": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz",
diff --git a/blocks/eda-frontend/package.json b/blocks/eda-frontend/package.json
index 680e9ebb..15755c5b 100644
--- a/blocks/eda-frontend/package.json
+++ b/blocks/eda-frontend/package.json
@@ -15,7 +15,7 @@
"highcharts-react-official": "^3.2.2",
"mxgraph": "^4.2.2",
"prop-types": "^15.8.1",
- "query-string": "^9.2.1",
+ "query-string": "^9.2.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-loader-spinner": "^6.1.6",
@@ -47,14 +47,14 @@
]
},
"devDependencies": {
- "@babel/eslint-parser": "^7.27.5",
- "eslint": "^9.30.0",
+ "@babel/eslint-parser": "^7.28.0",
+ "eslint": "^9.31.0",
"eslint-plugin-import": "^2.32.0",
- "eslint-plugin-n": "^17.20.0",
+ "eslint-plugin-n": "^17.21.0",
"eslint-plugin-promise": "^7.2.1",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
- "globals": "^16.2.0",
+ "globals": "^16.3.0",
"react-dev-utils": "^12.0.1",
"react-scripts": "^5.0.1",
"source-map-explorer": "^2.5.2"
diff --git a/blocks/eda-frontend/public/css/common.css b/blocks/eda-frontend/public/css/common.css
new file mode 100644
index 00000000..72dbc130
--- /dev/null
+++ b/blocks/eda-frontend/public/css/common.css
@@ -0,0 +1,192 @@
+div.mxRubberband {
+ position: absolute;
+ overflow: hidden;
+ border-style: solid;
+ border-width: 1px;
+ border-color: #0000FF;
+ background: #0077FF;
+}
+
+.mxCellEditor {
+ background: url(data:image/gif;base64,R0lGODlhMAAwAIAAAP///wAAACH5BAEAAAAALAAAAAAwADAAAAIxhI+py+0Po5y02ouz3rz7D4biSJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8egpAAA7);
+ _background: url('../images/transparent.gif');
+ border-color: transparent;
+ border-style: solid;
+ display: inline-block;
+ position: absolute;
+ overflow: visible;
+ word-wrap: normal;
+ border-width: 0;
+ min-width: 1px;
+ resize: none;
+ padding: 0px;
+ margin: 0px;
+}
+
+.mxPlainTextEditor * {
+ padding: 0px;
+ margin: 0px;
+}
+
+div.mxWindow {
+ -webkit-box-shadow: 3px 3px 12px #C0C0C0;
+ -moz-box-shadow: 3px 3px 12px #C0C0C0;
+ box-shadow: 3px 3px 12px #C0C0C0;
+ background: url(data:image/gif;base64,R0lGODlhGgAUAIAAAOzs7PDw8CH5BAAAAAAALAAAAAAaABQAAAIijI+py70Ao5y02lud3lzhD4ZUR5aPiKajyZbqq7YyB9dhAQA7);
+ _background: url('../images/window.gif');
+ border: 1px solid #c3c3c3;
+ position: absolute;
+ overflow: hidden;
+ z-index: 1;
+}
+
+table.mxWindow {
+ border-collapse: collapse;
+ table-layout: fixed;
+ font-family: Arial;
+ font-size: 8pt;
+}
+
+td.mxWindowTitle {
+ background: url(data:image/gif;base64,R0lGODlhFwAXAMQAANfX18rKyuHh4c7OzsDAwMHBwc/Pz+Li4uTk5NHR0dvb2+jo6O/v79/f3/n5+dnZ2dbW1uPj44yMjNPT0+Dg4N3d3ebm5szMzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAAAAAAALAAAAAAXABcAAAWQICESxWiW5Ck6bOu+MMvMdG3f86LvfO/rlqBwSCwaj8ikUohoOp/QaDNCrVqvWKpgezhsv+AwmEIum89ocmPNbrvf64p8Tq/b5Yq8fs/v5x+AgYKDhIAAh4iJiouHEI6PkJGSjhOVlpeYmZUJnJ2en6CcBqMDpaanqKgXq6ytrq+rAbKztLW2shK5uru8vbkhADs=) repeat-x;
+ _background: url('../images/window-title.gif') repeat-x;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ text-align: center;
+ font-weight: bold;
+ overflow: hidden;
+ height: 13px;
+ padding: 2px;
+ padding-top: 4px;
+ padding-bottom: 6px;
+ color: black;
+}
+
+td.mxWindowPane {
+ vertical-align: top;
+ padding: 0px;
+}
+
+div.mxWindowPane {
+ overflow: hidden;
+ position: relative;
+}
+
+td.mxWindowPane td {
+ font-family: Arial;
+ font-size: 8pt;
+}
+
+td.mxWindowPane input,
+td.mxWindowPane select,
+td.mxWindowPane textarea,
+td.mxWindowPane radio {
+ border-color: #8C8C8C;
+ border-style: solid;
+ border-width: 1px;
+ font-family: Arial;
+ font-size: 8pt;
+ padding: 1px;
+}
+
+td.mxWindowPane button {
+ background: url(data:image/gif;base64,R0lGODlhCgATALMAAP7+/t7e3vj4+Ojo6OXl5e/v7/n5+fb29vPz8/39/e3t7fHx8e7u7v///wAAAAAAACH5BAAAAAAALAAAAAAKABMAAAQ2MMlJhb0Y6c2X/2AhjiRjnqiirizqMkEsz0Rt30Ou7y8K/ouDcEg0GI9IgHLJbDif0Kh06owAADs=) repeat-x;
+ _background: url('../images/button.gif') repeat-x;
+ font-family: Arial;
+ font-size: 8pt;
+ padding: 2px;
+ float: left;
+}
+
+img.mxToolbarItem {
+ margin-right: 6px;
+ margin-bottom: 6px;
+ border-width: 1px;
+}
+
+select.mxToolbarCombo {
+ vertical-align: top;
+ border-style: inset;
+ border-width: 2px;
+}
+
+div.mxToolbarComboContainer {
+ padding: 2px;
+}
+
+img.mxToolbarMode {
+ margin: 2px;
+ margin-right: 4px;
+ margin-bottom: 4px;
+ border-width: 0px;
+}
+
+img.mxToolbarModeSelected {
+ margin: 0px;
+ margin-right: 2px;
+ margin-bottom: 2px;
+ border-width: 2px;
+ border-style: inset;
+}
+
+div.mxTooltip {
+ -webkit-box-shadow: 3px 3px 12px #C0C0C0;
+ -moz-box-shadow: 3px 3px 12px #C0C0C0;
+ box-shadow: 3px 3px 12px #C0C0C0;
+ background: #FFFFCC;
+ border-style: solid;
+ border-width: 1px;
+ border-color: black;
+ font-family: Arial;
+ font-size: 8pt;
+ position: absolute;
+ cursor: default;
+ padding: 4px;
+ color: black;
+}
+
+div.mxPopupMenu {
+ -webkit-box-shadow: 3px 3px 12px #C0C0C0;
+ -moz-box-shadow: 3px 3px 12px #C0C0C0;
+ box-shadow: 3px 3px 12px #C0C0C0;
+ background: url(data:image/gif;base64,R0lGODlhGgAUAIAAAOzs7PDw8CH5BAAAAAAALAAAAAAaABQAAAIijI+py70Ao5y02lud3lzhD4ZUR5aPiKajyZbqq7YyB9dhAQA7);
+ _background: url('../images/window.gif');
+ position: absolute;
+ border-style: solid;
+ border-width: 1px;
+ border-color: black;
+}
+
+table.mxPopupMenu {
+ border-collapse: collapse;
+ margin-top: 1px;
+ margin-bottom: 1px;
+}
+
+tr.mxPopupMenuItem {
+ color: black;
+ cursor: pointer;
+}
+
+tr.mxPopupMenuItemHover {
+ background-color: #000066;
+ color: #FFFFFF;
+ cursor: pointer;
+}
+
+td.mxPopupMenuItem {
+ padding: 2px 30px 2px 10px;
+ white-space: nowrap;
+ font-family: Arial;
+ font-size: 8pt;
+}
+
+td.mxPopupMenuIcon {
+ background-color: #D0D0D0;
+ padding: 2px 4px 2px 4px;
+}
+
+.mxDisabled {
+ opacity: 0.2 !important;
+ cursor: default !important;
+} \ No newline at end of file
diff --git a/blocks/eda-frontend/src/App.js b/blocks/eda-frontend/src/App.js
index d28c1296..1ceed868 100644
--- a/blocks/eda-frontend/src/App.js
+++ b/blocks/eda-frontend/src/App.js
@@ -15,17 +15,13 @@ import NotFound from './pages/NotFound'
import SchematicEditor from './pages/SchematicEditor'
import SignUp from './pages/signUp'
import { loadUser } from './redux/authSlice'
+import api from './utils/Api'
// Controls Private routes, this are accessible for authenticated users. [ e.g : dashboard ]
// and restricted routes disabled for authenticated users. [ e.g : login , signup ]
const PrivateRoute = ({ component: Component, ...rest }) => {
const isAuthenticated = useSelector(state => state.auth.isAuthenticated)
const isLoading = useSelector(state => state.auth.isLoading)
- const dispatch = useDispatch()
-
- useEffect(() => {
- dispatch(loadUser())
- }, [dispatch])
return (
<Route
@@ -50,11 +46,6 @@ PrivateRoute.propTypes = {
const PublicRoute = ({ component: Component, restricted, nav, ...rest }) => {
const isAuthenticated = useSelector(state => state.auth.isAuthenticated)
const isLoading = useSelector(state => state.auth.isLoading)
- const dispatch = useDispatch()
-
- useEffect(() => {
- dispatch(loadUser())
- }, [dispatch])
return (
<Route
@@ -80,6 +71,24 @@ PublicRoute.propTypes = {
}
const App = () => {
+ const dispatch = useDispatch()
+
+ useEffect(() => {
+ const initializeCsrf = async () => {
+ try {
+ await api.get('init')
+ } catch (err) {
+ console.error('Failed to initialize csrf:', err)
+ }
+ }
+
+ initializeCsrf()
+ }, [])
+
+ useEffect(() => {
+ dispatch(loadUser())
+ }, [dispatch])
+
return (
// Handles Routing for an application
<HashRouter>
diff --git a/blocks/eda-frontend/src/components/Dashboard/DashboardSidebar.js b/blocks/eda-frontend/src/components/Dashboard/DashboardSidebar.js
index f05203e2..01450f10 100644
--- a/blocks/eda-frontend/src/components/Dashboard/DashboardSidebar.js
+++ b/blocks/eda-frontend/src/components/Dashboard/DashboardSidebar.js
@@ -1,5 +1,4 @@
-import { useEffect } from 'react'
-import { useDispatch, useSelector } from 'react-redux'
+import { useSelector } from 'react-redux'
import { Link as RouterLink } from 'react-router-dom'
import {
@@ -16,7 +15,6 @@ import {
import { deepPurple } from '@material-ui/core/colors'
import { makeStyles } from '@material-ui/core/styles'
-import { fetchSchematics } from '../../redux/dashboardSlice'
import { getUppercaseInitial } from '../../utils/GalleryUtils'
const useStyles = makeStyles((theme) => ({
@@ -54,13 +52,6 @@ export default function DashSidebar (_props) {
const user = useSelector(state => state.auth.user)
const schematics = useSelector(state => state.dashboard.schematics)
- const dispatch = useDispatch()
-
- // For Fetching Saved Schematics
- useEffect(() => {
- dispatch(fetchSchematics())
- }, [dispatch])
-
const button = 'My ' + process.env.REACT_APP_DIAGRAMS_NAME
const placeholder = 'Find your ' + process.env.REACT_APP_SMALL_DIAGRAM_NAME + '...'
return (
diff --git a/blocks/eda-frontend/src/components/Dashboard/ProgressPanel.js b/blocks/eda-frontend/src/components/Dashboard/ProgressPanel.js
index 908b4054..548727c1 100644
--- a/blocks/eda-frontend/src/components/Dashboard/ProgressPanel.js
+++ b/blocks/eda-frontend/src/components/Dashboard/ProgressPanel.js
@@ -54,19 +54,21 @@ function a11yProps (index) {
export default function ProgressPanel () {
const classes = useStyles()
const [value, setValue] = useState(0)
+ const isLoggingOut = useSelector(state => state.auth.isLoggingOut)
+ const schematics = useSelector(state => state.dashboard.schematics)
+
+ const dispatch = useDispatch()
const handleChange = (event, newValue) => {
setValue(newValue)
}
- const schematics = useSelector(state => state.dashboard.schematics)
-
- const dispatch = useDispatch()
-
// For Fetching Saved Schematics
useEffect(() => {
+ if (isLoggingOut) return
+
dispatch(fetchSchematics())
- }, [dispatch])
+ }, [dispatch, isLoggingOut])
const tab = 'Recent ' + process.env.REACT_APP_DIAGRAMS_NAME
const typography = 'You have not created any ' + process.env.REACT_APP_SMALL_DIAGRAM_NAME
diff --git a/blocks/eda-frontend/src/components/Dashboard/SchematicsList.js b/blocks/eda-frontend/src/components/Dashboard/SchematicsList.js
index 91c19dc9..55c4504b 100644
--- a/blocks/eda-frontend/src/components/Dashboard/SchematicsList.js
+++ b/blocks/eda-frontend/src/components/Dashboard/SchematicsList.js
@@ -1,12 +1,9 @@
-import { useEffect } from 'react'
-import { useDispatch, useSelector } from 'react-redux'
+import { useSelector } from 'react-redux'
import { Link as RouterLink } from 'react-router-dom'
import { Button, Card, CardActions, CardContent, Grid, Typography } from '@material-ui/core'
import { makeStyles } from '@material-ui/core/styles'
-import { fetchSchematics } from '../../redux/dashboardSlice'
-
import SchematicCard from './SchematicCard'
const useStyles = makeStyles({
@@ -60,13 +57,6 @@ export default function SchematicsList () {
const user = useSelector(state => state.auth.user)
const schematics = useSelector(state => state.dashboard.schematics)
- const dispatch = useDispatch()
-
- // For Fetching Saved Schematics
- useEffect(() => {
- dispatch(fetchSchematics())
- }, [dispatch])
-
const typography1 = 'You don\'t have any saved ' + process.env.REACT_APP_SMALL_DIAGRAMS_NAME + '...'
return (
<>
diff --git a/blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js b/blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js
index 73e3a1ac..5db83d44 100644
--- a/blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js
+++ b/blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js
@@ -5,7 +5,7 @@ import { useSelector } from 'react-redux'
import mxGraphFactory from 'mxgraph'
-import { styleToObject } from '../../../utils/GalleryUtils'
+import { styleToObject, objectToStyle } from '../../../utils/GalleryUtils'
import { getPortType, InputPort, OutputPort } from './ComponentDrag'
import { portSize, getParameter } from './SvgParser'
@@ -111,6 +111,33 @@ export function Rotate () {
}
}
+// vertically
+export function Flip () {
+ const cell = graph.getSelectionCell()
+ if (cell && cell.CellType === 'Component') {
+ const model = graph.getModel()
+ const currentStyle = model.getStyle(cell) || ''
+ const styleMap = styleToObject(currentStyle)
+
+ styleMap.flip = styleMap.flip === 'true' ? 'false' : 'true'
+ model.setStyle(cell, objectToStyle(styleMap))
+ }
+}
+
+// horizontally
+export function Mirror () {
+ const cell = graph.getSelectionCell()
+ if (cell && cell.CellType === 'Component') {
+ const model = graph.getModel()
+ const currentStyle = model.getStyle(cell) || ''
+ const styleMap = styleToObject(currentStyle)
+
+ styleMap.mirror = styleMap.mirror === 'true' ? 'false' : 'true'
+
+ model.setStyle(cell, objectToStyle(styleMap))
+ }
+}
+
// PRINT PREVIEW OF SCHEMATIC
export function PrintPreview () {
const title = useSelector(state => state.saveSchematic.title)
diff --git a/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js b/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js
index b992db10..b91b43bd 100644
--- a/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js
+++ b/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js
@@ -24,6 +24,7 @@ import { makeStyles } from '@material-ui/core/styles'
import AddBoxOutlinedIcon from '@material-ui/icons/AddBoxOutlined'
import ClearAllIcon from '@material-ui/icons/ClearAll'
import CloseIcon from '@material-ui/icons/Close'
+import CompareArrowsIcon from '@material-ui/icons/CompareArrows'
import CreateNewFolderOutlinedIcon from '@material-ui/icons/CreateNewFolderOutlined'
import DeleteIcon from '@material-ui/icons/Delete'
import DescriptionIcon from '@material-ui/icons/Description'
@@ -64,6 +65,8 @@ import {
editorZoomIn,
editorZoomOut,
renderGalleryXML,
+ Flip,
+ Mirror,
saveXml
} from './Helper/ToolbarTools'
import {
@@ -512,7 +515,10 @@ export default function SchematicToolbar ({ _mobileClose, gridRef }) {
'pipe',
{ icon: <UndoIcon fontSize='small' />, label: 'Undo', action: editorUndo },
{ icon: <RedoIcon fontSize='small' />, label: 'Redo', action: editorRedo },
+ 'pipe',
{ icon: <RotateRightIcon fontSize='small' />, label: 'Rotate', action: Rotate },
+ { icon: <CompareArrowsIcon style={{ transform: 'rotate(90deg)' }} fontSize='small' />, label: 'Flip', action: Flip },
+ { icon: <CompareArrowsIcon fontSize='small' />, label: 'Mirror', action: Mirror },
'pipe',
{ icon: <ZoomInIcon fontSize='small' />, label: 'Zoom In', action: editorZoomIn },
{ icon: <ZoomOutIcon fontSize='small' />, label: 'Zoom Out', action: editorZoomOut },
diff --git a/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js b/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js
index 0c6cc51c..58d758b8 100644
--- a/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js
+++ b/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js
@@ -693,6 +693,37 @@ ImageExportDialog.propTypes = {
open: PropTypes.bool.isRequired
}
+function SchematicRow ({ sch, onClick, details, showDates = false }) {
+ return (
+ <TableRow key={sch.save_id}>
+ <TableCell align='center'>{sch.name}</TableCell>
+ <TableCell align='center'>
+ <Tooltip title={sch.description !== null ? sch.description : 'No description'}>
+ <span>
+ {sch.description !== null ? sch.description.slice(0, 30) + (sch.description.length < 30 ? '' : '...') : '-'}
+ </span>
+ </Tooltip>
+ </TableCell>
+ {showDates && (
+ <>
+ <TableCell align='center'>{getDate(sch.create_time)}</TableCell>
+ <TableCell align='center'>{getDate(sch.save_time)}</TableCell>
+ </>
+ )}
+ <TableCell align='center'>
+ <Button
+ size='small'
+ color='primary'
+ onClick={() => onClick(sch.save_id)}
+ variant={details.save_id === undefined ? 'outlined' : details.save_id !== sch.save_id ? 'outlined' : 'contained'}
+ >
+ Launch
+ </Button>
+ </TableCell>
+ </TableRow>
+ )
+}
+
// Dialog box to open saved Schematics
export function OpenSchDialog (props) {
const { open, close, openLocal } = props
@@ -753,32 +784,15 @@ export function OpenSchDialog (props) {
</TableHead>
<TableBody>
<>
- {GallerySchSample.map(
- (sch) => {
- return (
- <TableRow key={sch.save_id}>
- <TableCell align='center'>{sch.name}</TableCell>
- <TableCell align='center'>
- <Tooltip title={sch.description !== null ? sch.description : 'No description'}>
- <span>
- {sch.description !== null ? sch.description.slice(0, 30) + (sch.description.length < 30 ? '' : '...') : '-'}
- </span>
- </Tooltip>
- </TableCell>
- <TableCell align='center'>
- <Button
- size='small'
- color='primary'
- onClick={() => { dispatch(fetchDiagram(sch.save_id)) }}
- variant={details.save_id === undefined ? 'outlined' : details.save_id !== sch.save_id ? 'outlined' : 'contained'}
- >
- Launch
- </Button>
- </TableCell>
- </TableRow>
- )
- }
- )}
+ {GallerySchSample.map((sch) => (
+ <SchematicRow
+ key={sch.save_id}
+ sch={sch}
+ onClick={(id) => dispatch(fetchDiagram(id))}
+ details={details}
+ showDates={false}
+ />
+ ))}
</>
</TableBody>
</Table>
@@ -803,34 +817,15 @@ export function OpenSchDialog (props) {
</TableHead>
<TableBody>
<>
- {schematics.map(
- (sch) => {
- return (
- <TableRow key={sch.save_id}>
- <TableCell align='center'>{sch.name}</TableCell>
- <TableCell align='center'>
- <Tooltip title={sch.description !== null ? sch.description : 'No description'}>
- <span>
- {sch.description !== null ? sch.description.slice(0, 30) + (sch.description.length < 30 ? '' : '...') : '-'}
- </span>
- </Tooltip>
- </TableCell>
- <TableCell align='center'>{getDate(sch.create_time)}</TableCell>
- <TableCell align='center'>{getDate(sch.save_time)}</TableCell>
- <TableCell align='center'>
- <Button
- size='small'
- color='primary'
- onClick={() => { dispatch(fetchSchematic(sch.save_id)) }}
- variant={details.save_id === undefined ? 'outlined' : details.save_id !== sch.save_id ? 'outlined' : 'contained'}
- >
- Launch
- </Button>
- </TableCell>
- </TableRow>
- )
- }
- )}
+ {schematics.map((sch) => (
+ <SchematicRow
+ key={sch.save_id}
+ sch={sch}
+ onClick={(id) => dispatch(fetchSchematic(id))}
+ details={details}
+ showDates={true}
+ />
+ ))}
</>
</TableBody>
</Table>
diff --git a/blocks/eda-frontend/src/pages/Login.js b/blocks/eda-frontend/src/pages/Login.js
index e7ca5eac..f1aefedd 100644
--- a/blocks/eda-frontend/src/pages/Login.js
+++ b/blocks/eda-frontend/src/pages/Login.js
@@ -73,14 +73,21 @@ export default function SignIn (props) {
}
}, [dispatch, props.location.search])
- const [username, setUsername] = useState('')
+ const rememberedUsername = localStorage.getItem('rememberedUsername') || ''
+ const [username, setUsername] = useState(rememberedUsername)
const [password, setPassword] = useState('')
const [showPassword, setShowPassword] = useState(false)
+ const [rememberMe, setRememberMe] = useState(!!rememberedUsername)
const handleClickShowPassword = () => setShowPassword(!showPassword)
const handleMouseDownPassword = () => setShowPassword(!showPassword)
// Function call for normal user login.
const handleLogin = () => {
+ if (rememberMe) {
+ localStorage.setItem('rememberedUsername', username)
+ } else {
+ localStorage.removeItem('rememberedUsername')
+ }
dispatch(login({ email: username, password, toUrl: url }))
}
@@ -154,7 +161,13 @@ export default function SignIn (props) {
autoComplete='current-password'
/>
<FormControlLabel
- control={<Checkbox value='remember' color='primary' />}
+ control={
+ <Checkbox
+ color='primary'
+ checked={rememberMe}
+ onChange={e => setRememberMe(e.target.checked)}
+ />
+ }
label='Remember me'
/>
<Button
diff --git a/blocks/eda-frontend/src/redux/authSlice.js b/blocks/eda-frontend/src/redux/authSlice.js
index ee5705c1..21087d52 100644
--- a/blocks/eda-frontend/src/redux/authSlice.js
+++ b/blocks/eda-frontend/src/redux/authSlice.js
@@ -7,6 +7,7 @@ const tokenKey = process.env.REACT_APP_NAME + '_token'
const initialState = {
token: localStorage.getItem(tokenKey),
isAuthenticated: false,
+ isLoggingOut: false,
isRegistered: false,
isLoading: false,
user: null,
@@ -17,9 +18,9 @@ const initialState = {
// Api call for maintaining user login state throughout the application
export const loadUser = createAsyncThunk(
'auth/loadUser',
- async (_, { getState, rejectWithValue }) => {
+ async (tokenFromLogin, { getState, rejectWithValue }) => {
// Get token from localstorage
- const token = getState().auth.token
+ const token = tokenFromLogin || getState().auth.token
if (!token) return rejectWithValue('No token found')
// add headers
@@ -32,7 +33,7 @@ export const loadUser = createAsyncThunk(
try {
const res = await api.get('auth/users/me/', config)
- if (res.status === 200) {
+ if ([200, 201, 204].includes(res.status)) {
return res.data
}
return rejectWithValue(res.data || 'Failed to load user')
@@ -69,17 +70,18 @@ export const login = createAsyncThunk(
email,
password
})
- if (res.status === 200) {
- localStorage.setItem(tokenKey, res.data.auth_token)
+ if ([200, 201, 204].includes(res.status)) {
+ const token = res.data.auth_token
+ localStorage.setItem(tokenKey, token)
if (toUrl === '') {
- dispatch(loadUser())
+ dispatch(loadUser(token))
} else if (!allowedUrls.includes(toUrl)) {
console.log('Not redirecting to', toUrl)
- dispatch(loadUser())
+ dispatch(loadUser(token))
} else {
window.open(toUrl, '_self')
}
- return res.data.auth_token
+ return token
}
return loginError(res, rejectWithValue)
@@ -117,7 +119,7 @@ export const signUp = createAsyncThunk(
password,
re_password: reenterPassword
})
- if (res.status === 200) {
+ if ([200, 201, 204].includes(res.status)) {
return 'Successfully Signed Up! A verification link has been sent to your email account.'
}
@@ -165,7 +167,7 @@ export const googleLogin = createAsyncThunk(
async (host, { rejectWithValue }) => {
try {
const res = await api.get(`auth/o/google-oauth2/?redirect_uri=${host}/api/auth/google-callback`)
- if (res.status === 200) {
+ if ([200, 201, 204].includes(res.status)) {
// Open google login page
window.open(res.data.authorization_url, '_self')
return res.data.authorization_url
@@ -185,7 +187,7 @@ export const githubLogin = createAsyncThunk(
async (host, { rejectWithValue }) => {
try {
const res = await api.get(`auth/o/github/?redirect_uri=${host}/api/auth/github-callback`)
- if (res.status === 200) {
+ if ([200, 201, 204].includes(res.status)) {
// Open GitHub login page
window.open(res.data.authorization_url, '_self')
return res.data.authorization_url
@@ -228,7 +230,6 @@ const authSlice = createSlice({
state.isAuthenticated = false
})
.addCase(login.fulfilled, (state, action) => {
- state.isLoading = false
state.token = action.payload
state.errors = ''
})
@@ -243,9 +244,6 @@ const authSlice = createSlice({
state.isLoading = true
state.isAuthenticated = false
})
- .addCase(googleLogin.fulfilled, (state) => {
- state.isLoading = false
- })
.addCase(googleLogin.rejected, (state, action) => {
state.isLoading = false
state.token = null
@@ -257,9 +255,6 @@ const authSlice = createSlice({
state.isLoading = true
state.isAuthenticated = false
})
- .addCase(githubLogin.fulfilled, (state) => {
- state.isLoading = false
- })
.addCase(githubLogin.rejected, (state, action) => {
state.isLoading = false
state.token = null
@@ -281,8 +276,13 @@ const authSlice = createSlice({
state.isRegistered = false
state.regErrors = action.payload
})
+ .addCase(logout.pending, (state) => {
+ state.isLoading = true
+ state.isLoggingOut = true
+ })
.addCase(logout.fulfilled, (state) => {
state.isLoading = false
+ state.isLoggingOut = false
state.token = null
state.user = null
state.isAuthenticated = false
diff --git a/blocks/eda-frontend/src/redux/dashboardSlice.js b/blocks/eda-frontend/src/redux/dashboardSlice.js
index 753b5287..2c32875a 100644
--- a/blocks/eda-frontend/src/redux/dashboardSlice.js
+++ b/blocks/eda-frontend/src/redux/dashboardSlice.js
@@ -2,6 +2,8 @@ import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
import api from '../utils/Api'
+import { logout } from './authSlice'
+
const initialState = {
isLoading: false,
schematics: [],
@@ -106,6 +108,9 @@ const dashboardSlice = createSlice({
state.isLoading = false
state.gallery = []
})
+ .addCase(logout.fulfilled, (state) => {
+ state.schematics = []
+ })
}
})
diff --git a/blocks/eda-frontend/src/utils/GalleryUtils.js b/blocks/eda-frontend/src/utils/GalleryUtils.js
index 7e6a6bf7..37322592 100644
--- a/blocks/eda-frontend/src/utils/GalleryUtils.js
+++ b/blocks/eda-frontend/src/utils/GalleryUtils.js
@@ -176,6 +176,17 @@ export const styleToObject = (style) => {
return styleObject
}
+export const objectToStyle = (styleObject) => {
+ let style = styleObject.default
+ for (const [key, value] of Object.entries(styleObject)) {
+ if (key === 'default' || value == null || value === '') {
+ continue
+ }
+ style += `;${key}=${value}`
+ }
+ return style
+}
+
export const saveToFile = (filename, filetype, data) => {
const blob = new Blob([data], { type: filetype + ';charset=utf-8' })
saveAs(blob, filename)
diff --git a/blocks/init.sh b/blocks/init.sh
index ef98711c..16215a00 100755
--- a/blocks/init.sh
+++ b/blocks/init.sh
@@ -7,8 +7,8 @@ PASSWORD=''
rm -f xcosblocks.sqlite3
-./manage.py migrate -v0
-./manage.py loaddata xcosblocks
+python manage.py migrate -v0
+python manage.py loaddata -v0 saveAPI xcosblocks
echo "from authAPI.models import User; User.objects.create_superuser('$EMAIL', '$EMAIL', '$PASSWORD')" |
- ./manage.py shell
+ python manage.py shell
diff --git a/blocks/simulationAPI/helpers/ngspice_helper.py b/blocks/simulationAPI/helpers/ngspice_helper.py
index b41b13a9..1dcd1e00 100644
--- a/blocks/simulationAPI/helpers/ngspice_helper.py
+++ b/blocks/simulationAPI/helpers/ngspice_helper.py
@@ -1,6 +1,6 @@
import json
import os
-from os.path import abspath, join, splitext
+from os.path import join, splitext
import re
import subprocess
from celery import current_task
@@ -17,30 +17,6 @@ from simulationAPI.helpers.scilab_manager import start_scilab, upload, remove, r
logger = get_task_logger(__name__)
XmlToXcos = join(settings.BASE_DIR, 'Xcos/XmlToXcos.sh')
-SCILAB_DIR = abspath(settings.SCILAB_DIR)
-SCILAB = join(SCILAB_DIR, 'bin', 'scilab-adv-cli')
-# handle scilab startup
-SCILAB_START = (
- "try;funcprot(0);lines(0,120);"
- "clearfun('messagebox');"
- "function messagebox(msg,title,icon,buttons,modal),disp(msg),endfunction;"
- "funcprot(1);"
- "catch;[error_message,error_number,error_line,error_func]=lasterror();"
- "disp(error_message,error_number,error_line,error_func);exit(3);end;"
-)
-
-SCILAB_END = (
- "catch;[error_message,error_number,error_line,error_func]=lasterror();"
- "disp(error_message,error_number,error_line,error_func);exit(2);end;exit;"
-)
-SCILAB_CMD = [SCILAB,
- "-noatomsautoload",
- "-nogui",
- "-nouserstartup",
- "-nb",
- "-nw",
- "-e", SCILAB_START]
-LOGFILEFD = 123
START_STATES = ["STARTED"]
END_STATES = ["SUCCESS", "FAILURE", "CANCELED"]
diff --git a/blocks/simulationAPI/helpers/scilab_manager.py b/blocks/simulationAPI/helpers/scilab_manager.py
index ce420eee..528cda5d 100644
--- a/blocks/simulationAPI/helpers/scilab_manager.py
+++ b/blocks/simulationAPI/helpers/scilab_manager.py
@@ -86,8 +86,7 @@ def secure_filename(filename: str) -> str:
def makedirs(dirname, dirtype=None):
- if not exists(dirname):
- os.makedirs(dirname)
+ os.makedirs(dirname, exist_ok=True)
def rmdir(dirname, dirtype=None):
diff --git a/blocks/xcos2xml/blocks/ConstantVoltage.xsl b/blocks/xcos2xml/blocks/ConstantVoltage.xsl
index 727bd0f0..34622121 100644
--- a/blocks/xcos2xml/blocks/ConstantVoltage.xsl
+++ b/blocks/xcos2xml/blocks/ConstantVoltage.xsl
@@ -44,10 +44,8 @@
<xsl:apply-templates select="mxGeometry" />
<Object>
<xsl:attribute name="display_parameter">
- <!-- <xsl:value-of select="format-number(0.01 * 1000, '0')" />
- <xsl:text> m</xsl:text> -->
<xsl:call-template name="si-format">
- <xsl:with-param name="num" select="number(*[@as='exprs']/data[1]/@value)" />
+ <xsl:with-param name="expr" select="*[@as='exprs']/data[1]/@value" />
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="as">displayProperties</xsl:attribute>
diff --git a/blocks/xcos2xml/blocks/Resistor.xsl b/blocks/xcos2xml/blocks/Resistor.xsl
index 925ce561..cda89f2d 100644
--- a/blocks/xcos2xml/blocks/Resistor.xsl
+++ b/blocks/xcos2xml/blocks/Resistor.xsl
@@ -44,9 +44,8 @@
<xsl:apply-templates select="mxGeometry" />
<Object>
<xsl:attribute name="display_parameter">
- <!-- <xsl:value-of select="si-format(number(*[@as='exprs']/data[1]/@value), '0')" /> -->
<xsl:call-template name="si-format">
- <xsl:with-param name="num" select="number(*[@as='exprs']/data[1]/@value)" />
+ <xsl:with-param name="expr" select="*[@as='exprs']/data[1]/@value" />
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="as">displayProperties</xsl:attribute>
diff --git a/blocks/xcos2xml/blocks/SUPER_f.xsl b/blocks/xcos2xml/blocks/SUPER_f.xsl
index 9bd1a5cc..cca736af 100644
--- a/blocks/xcos2xml/blocks/SUPER_f.xsl
+++ b/blocks/xcos2xml/blocks/SUPER_f.xsl
@@ -1,8 +1,8 @@
<xsl:template match="SuperBlock">
- <xsl:variable name="explicitInputPorts" select="count(SuperBlockDiagram/mxGraphModel/root/ExplicitOutBlock)" />
- <xsl:variable name="implicitInputPorts" select="count(SuperBlockDiagram/mxGraphModel/root/ImplicitOutBlock)" />
- <xsl:variable name="explicitOutputPorts" select="count(SuperBlockDiagram/mxGraphModel/root/ExplicitInBlock)" />
- <xsl:variable name="implicitOutputPorts" select="count(SuperBlockDiagram/mxGraphModel/root/ImplicitInBlock)" />
+ <xsl:variable name="explicitInputPorts" select="count(SuperBlockDiagram/mxGraphModel/root/ExplicitInBlock)" />
+ <xsl:variable name="implicitInputPorts" select="count(SuperBlockDiagram/mxGraphModel/root/ImplicitInBlock)" />
+ <xsl:variable name="explicitOutputPorts" select="count(SuperBlockDiagram/mxGraphModel/root/ExplicitOutBlock)" />
+ <xsl:variable name="implicitOutputPorts" select="count(SuperBlockDiagram/mxGraphModel/root/ImplicitOutBlock)" />
<xsl:variable name="controlPorts" select="count(SuperBlockDiagram/mxGraphModel/root/EventInBlock)" />
<xsl:variable name="commandPorts" select="count(SuperBlockDiagram/mxGraphModel/root/EventOutBlock)" />
<xsl:element name="mxCell">
diff --git a/blocks/xcos2xml/blocks/TEXT_f.xsl b/blocks/xcos2xml/blocks/TEXT_f.xsl
index 72e5ca91..9c0ee871 100644
--- a/blocks/xcos2xml/blocks/TEXT_f.xsl
+++ b/blocks/xcos2xml/blocks/TEXT_f.xsl
@@ -7,7 +7,12 @@
<xsl:variable name="commandPorts">0</xsl:variable>
<xsl:element name="mxCell">
<xsl:attribute name="style">
- <xsl:value-of select="@style" />
+ <xsl:choose>
+ <xsl:when test="@style != ''">
+ <xsl:value-of select="@style" />
+ </xsl:when>
+ <xsl:otherwise>TEXT_f</xsl:otherwise>
+ </xsl:choose>
</xsl:attribute>
<xsl:attribute name="id">
<xsl:value-of select="@id" />
diff --git a/blocks/xcos2xml/head.xsl b/blocks/xcos2xml/head.xsl
index 22fb992c..5e58e0c9 100644
--- a/blocks/xcos2xml/head.xsl
+++ b/blocks/xcos2xml/head.xsl
@@ -20,85 +20,70 @@
</xsl:choose>
</xsl:template>
- <xsl:template name="si-format">
- <xsl:param name="num" />
+ <xsl:template name="eval-rational">
+ <xsl:param name="expr"/>
- <!-- Compute absolute value manually -->
- <xsl:variable name="absNum">
- <xsl:choose>
- <xsl:when test="$num &lt; 0"><xsl:value-of select="-$num" /></xsl:when>
- <xsl:otherwise><xsl:value-of select="$num" /></xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="contains($expr, '/')">
+ <xsl:variable name="num" select="number(substring-before($expr, '/'))" />
+ <xsl:variable name="den" select="number(substring-after($expr, '/'))" />
+ <xsl:value-of select="$num div $den" />
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="number($expr)" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
- <!-- Compute exponent -->
- <xsl:variable name="exponent">
- <xsl:choose>
- <xsl:when test="$absNum = 0">0</xsl:when>
- <xsl:otherwise>
- <xsl:call-template name="compute-exp">
- <xsl:with-param name="n" select="$absNum" />
- <xsl:with-param name="exp" select="0" />
- </xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
+ <xsl:template name="si-format">
+ <xsl:param name="expr" />
- <!-- Define SI prefixes -->
- <xsl:choose>
- <xsl:when test="$exponent &gt;= -2 and $exponent &lt;= 0">
- <xsl:value-of select="round($num div 1E-3)" /> m
- </xsl:when>
- <xsl:when test="$exponent &gt;= -5 and $exponent &lt;= -3">
- <xsl:value-of select="round($num div 1E-6)" /> &#956; <!-- Unicode for μ -->
- </xsl:when>
- <xsl:when test="$exponent &gt;= -8 and $exponent &lt;= -6">
- <xsl:value-of select="round($num div 1E-9)" /> n
- </xsl:when>
- <xsl:when test="$exponent &gt;= -11 and $exponent &lt;= -9">
- <xsl:value-of select="round($num div 1E-12)" /> p
- </xsl:when>
- <xsl:when test="$exponent &gt;= 1 and $exponent &lt;= 3">
- <xsl:value-of select="round($num div 1)" />
- </xsl:when>
- <xsl:when test="$exponent &gt;= 4 and $exponent &lt;= 6">
- <xsl:value-of select="round($num div 1E3)" /> k</xsl:when>
- <xsl:when test="$exponent &gt;= 7 and $exponent &lt;= 9">
- <xsl:value-of select="round($num div 1E6)" /> M
- </xsl:when>
- <xsl:when test="$exponent &gt;= 10 and $exponent &lt;= 12">
- <xsl:value-of select="round($num div 1E9)" /> G
- </xsl:when>
- <xsl:when test="$exponent &gt;= 13 and $exponent &lt;= 15">
- <xsl:value-of select="round($num div 1E12)" /> T
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$num" /> 10^<xsl:value-of select="$exponent " />
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
- <!-- Recursive template to compute the exponent -->
- <xsl:template name="compute-exp">
- <xsl:param name="n" />
- <xsl:param name="exp" />
+ <xsl:variable name="num">
+ <xsl:call-template name="eval-rational">
+ <xsl:with-param name="expr" select="$expr" />
+ </xsl:call-template>
+ </xsl:variable>
- <xsl:choose>
- <xsl:when test="$n &lt; 1">
- <xsl:call-template name="compute-exp">
- <xsl:with-param name="n" select="$n * 10" />
- <xsl:with-param name="exp" select="$exp - 1" />
- </xsl:call-template>
- </xsl:when>
- <xsl:when test="$n &gt;= 10">
- <xsl:call-template name="compute-exp">
- <xsl:with-param name="n" select="$n div 10" />
- <xsl:with-param name="exp" select="$exp + 1" />
- </xsl:call-template>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$exp" />
- </xsl:otherwise>
- </xsl:choose>
+ <xsl:choose>
+ <xsl:when test="number($num) &gt;= 1000000000000">
+ <xsl:value-of select="format-number($num div 1000000000000, '#.##')" />
+ <xsl:text> T</xsl:text>
+ </xsl:when>
+ <xsl:when test="number($num) &gt;= 1000000000">
+ <xsl:value-of select="format-number($num div 1000000000, '#.##')" />
+ <xsl:text> G</xsl:text>
+ </xsl:when>
+ <xsl:when test="number($num) &gt;= 1000000">
+ <xsl:value-of select="format-number($num div 1000000, '#.##')" />
+ <xsl:text> M</xsl:text>
+ </xsl:when>
+ <xsl:when test="number($num) &gt;= 1000">
+ <xsl:value-of select="format-number($num div 1000, '#.##')" />
+ <xsl:text> k</xsl:text>
+ </xsl:when>
+ <xsl:when test="number($num) &gt;= 1">
+ <xsl:value-of select="format-number($num, '#.##')" />
+ </xsl:when>
+ <xsl:when test="number($num) &gt;= 0.001">
+ <xsl:value-of select="format-number($num div 0.001, '#.##')" />
+ <xsl:text> m</xsl:text>
+ </xsl:when>
+ <xsl:when test="number($num) &gt;= 0.000001">
+ <xsl:value-of select="format-number($num div 0.000001, '#.##')" />
+ <xsl:text> &#956;</xsl:text>
+ </xsl:when>
+ <xsl:when test="number($num) &gt;= 0.000000001">
+ <xsl:value-of select="format-number($num div 0.000000001, '#.##')" />
+ <xsl:text> n</xsl:text>
+ </xsl:when>
+ <xsl:when test="number($num) &gt;= 0.000000000001">
+ <xsl:value-of select="format-number($num div 0.000000000001, '#.##')" />
+ <xsl:text> p</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="format-number($num, '#.##')" />
+ </xsl:otherwise>
+ </xsl:choose>
</xsl:template>
<xsl:output method="xml" indent="no" />
@@ -279,59 +264,61 @@
</xsl:template>
<xsl:template name="generate-block">
+ <xsl:param name="style"/>
+ <xsl:param name="id"/>
<xsl:param name="explicitInputPorts"/>
<xsl:param name="implicitInputPorts"/>
<xsl:param name="explicitOutputPorts"/>
<xsl:param name="implicitOutputPorts"/>
<xsl:param name="controlPorts"/>
<xsl:param name="commandPorts"/>
- <xsl:param name="blockId"/>
- <xsl:param name="style"/>
<xsl:param name="simulationFunction"/>
<xsl:param name="display_parameter"/>
<xsl:param name="data"/>
<xsl:element name="mxCell">
- <xsl:attribute name="style"><xsl:value-of select="$style"/></xsl:attribute>
- <xsl:attribute name="id"><xsl:value-of select="$blockId"/></xsl:attribute>
- <xsl:attribute name="vertex">1</xsl:attribute>
- <xsl:attribute name="connectable">0</xsl:attribute>
- <xsl:attribute name="CellType">Component</xsl:attribute>
- <xsl:attribute name="blockprefix">XCOS</xsl:attribute>
- <xsl:attribute name="explicitInputPorts"><xsl:value-of select="$explicitInputPorts"/></xsl:attribute>
- <xsl:attribute name="implicitInputPorts"><xsl:value-of select="$implicitInputPorts"/></xsl:attribute>
- <xsl:attribute name="explicitOutputPorts"><xsl:value-of select="$explicitOutputPorts"/></xsl:attribute>
- <xsl:attribute name="implicitOutputPorts"><xsl:value-of select="$implicitOutputPorts"/></xsl:attribute>
- <xsl:attribute name="controlPorts"><xsl:value-of select="$controlPorts"/></xsl:attribute>
- <xsl:attribute name="commandPorts"><xsl:value-of select="$commandPorts"/></xsl:attribute>
- <xsl:attribute name="simulationFunction"><xsl:value-of select="$simulationFunction"/></xsl:attribute>
- <xsl:attribute name="sourceVertex">0</xsl:attribute>
- <xsl:attribute name="targetVertex">0</xsl:attribute>
- <xsl:attribute name="tarx">0</xsl:attribute>
- <xsl:attribute name="tary">0</xsl:attribute>
+ <xsl:attribute name="style"><xsl:value-of select="$style"/></xsl:attribute>
+ <xsl:attribute name="id"><xsl:value-of select="$id"/></xsl:attribute>
+ <xsl:attribute name="vertex">1</xsl:attribute>
+ <xsl:attribute name="connectable">0</xsl:attribute>
+ <xsl:attribute name="CellType">Component</xsl:attribute>
+ <xsl:attribute name="blockprefix">XCOS</xsl:attribute>
+ <xsl:attribute name="explicitInputPorts"><xsl:value-of select="$explicitInputPorts"/></xsl:attribute>
+ <xsl:attribute name="implicitInputPorts"><xsl:value-of select="$implicitInputPorts"/></xsl:attribute>
+ <xsl:attribute name="explicitOutputPorts"><xsl:value-of select="$explicitOutputPorts"/></xsl:attribute>
+ <xsl:attribute name="implicitOutputPorts"><xsl:value-of select="$implicitOutputPorts"/></xsl:attribute>
+ <xsl:attribute name="controlPorts"><xsl:value-of select="$controlPorts"/></xsl:attribute>
+ <xsl:attribute name="commandPorts"><xsl:value-of select="$commandPorts"/></xsl:attribute>
+ <xsl:attribute name="simulationFunction"><xsl:value-of select="$simulationFunction"/></xsl:attribute>
+ <xsl:attribute name="sourceVertex">0</xsl:attribute>
+ <xsl:attribute name="targetVertex">0</xsl:attribute>
+ <xsl:attribute name="tarx">0</xsl:attribute>
+ <xsl:attribute name="tary">0</xsl:attribute>
- <xsl:apply-templates select="mxGeometry"/>
- <Object as="displayProperties">
+ <xsl:apply-templates select="mxGeometry"/>
+
+ <Object as="displayProperties">
<xsl:attribute name="display_parameter">
- <xsl:value-of select="$display_parameter"/>
+ <xsl:value-of select="$display_parameter"/>
</xsl:attribute>
- </Object>
- <Object as="parameter_values">
- <xsl:for-each select="$data">
- <xsl:attribute name="{concat('p', format-number(position() - 1, '000'), '_value')}">
- <xsl:value-of select="@value" />
- </xsl:attribute>
- </xsl:for-each>
- </Object>
+ </Object>
+
+ <Object as="parameter_values">
+ <xsl:for-each select="$data">
+ <xsl:attribute name="{concat('p', format-number(position() - 1, '000'), '_value')}">
+ <xsl:value-of select="@value" />
+ </xsl:attribute>
+ </xsl:for-each>
+ </Object>
</xsl:element>
<xsl:call-template name="port">
- <xsl:with-param name="id" select="$blockId"/>
- <xsl:with-param name="explicitInputPorts" select="$explicitInputPorts"/>
- <xsl:with-param name="explicitOutputPorts" select="$explicitOutputPorts"/>
- <xsl:with-param name="implicitInputPorts" select="$implicitInputPorts"/>
- <xsl:with-param name="implicitOutputPorts" select="$implicitOutputPorts"/>
- <xsl:with-param name="controlPorts" select="$controlPorts"/>
- <xsl:with-param name="commandPorts" select="$commandPorts"/>
+ <xsl:with-param name="id" select="$id"/>
+ <xsl:with-param name="explicitInputPorts" select="$explicitInputPorts"/>
+ <xsl:with-param name="explicitOutputPorts" select="$explicitOutputPorts"/>
+ <xsl:with-param name="implicitInputPorts" select="$implicitInputPorts"/>
+ <xsl:with-param name="implicitOutputPorts" select="$implicitOutputPorts"/>
+ <xsl:with-param name="controlPorts" select="$controlPorts"/>
+ <xsl:with-param name="commandPorts" select="$commandPorts"/>
</xsl:call-template>
</xsl:template>