diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 7c5703e..54253a2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -114,3 +114,11 @@ repos: hooks: - id: commitlint stages: [commit-msg] + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.1.0 + hooks: + - id: prettier + types_or: [ts, css, html, markdown] + additional_dependencies: + - 'prettier@^3.2.5' + - 'prettier-plugin-tailwindcss@^0.5.14' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c98c895..b5dd31f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,8 +76,7 @@ The key differences are: - **Docstrings**: The [Numpy style guide] applies here. - [numpy style guide]: - https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard + [numpy style guide]: https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard When writing docstrings for functions, use the imperative style, as per [PEP-257]). For example, write "Do X and Y" instead of "Does X and Y". @@ -124,7 +123,6 @@ The key differences are: typing related classes like `t.TypedDict`. - Use the new syntax and classes for typing introduced with Python 3.10. - Instead of `t.Tuple`, `t.List` etc. use the builtin classes `tuple`, `list` @@ -142,8 +140,7 @@ The key differences are: If you have set up black correctly, you don't need to worry about this though :) - [black code style]: - https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html + [black code style]: https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html - When working with `dict`s, consider using `t.TypedDict` instead of a more generic `dict[str, float|int|str]`-like annotation where possible, as the diff --git a/Dockerfile b/Dockerfile index 1e8b0a8..5ba7f75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,4 +43,4 @@ RUN chmod +x /entrypoint.sh ENV MODEL_ENTRYPOINT=/model RUN chmod -R 777 ./frontend/dist/ -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file +ENTRYPOINT ["/entrypoint.sh"] diff --git a/README.md b/README.md index 5485cfa..2cd5ac5 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ We see a larger non-MBSE crowd struggling with the things hidden in the model. W **Use cases**: -- Provide insights into / "spell-out" the model for non-MBSE stakeholders via document-a-like dynamic views that describe model elements in a human-readable form. -- Provide meaningful default views (that can be further customized) for the key elements to kickstart the model exploration. +- Provide insights into / "spell-out" the model for non-MBSE stakeholders via document-a-like dynamic views that describe model elements in a human-readable form. +- Provide meaningful default views (that can be further customized) for the key elements to kickstart the model exploration. There are a few more use cases but we will reveal them a bit later. diff --git a/capella_model_explorer/backend/explorer.py b/capella_model_explorer/backend/explorer.py index a248726..bed0266 100644 --- a/capella_model_explorer/backend/explorer.py +++ b/capella_model_explorer/backend/explorer.py @@ -181,14 +181,23 @@ def read_template(template_name: str): filters=filters, ) base["objects"] = [ - {"idx": obj.uuid, - "name": str( - obj.name if obj.name else ( - obj.long_name if hasattr(obj, "long_name") else "undefined") - )} for obj in objects + { + "idx": obj.uuid, + "name": str( + obj.name + if obj.name + else ( + obj.long_name + if hasattr(obj, "long_name") + else "undefined" + ) + ), + } + for obj in objects ] except Exception as e: import traceback + LOGGER.exception( "Error finding objects for template %s", template_name ) diff --git a/entrypoint.sh b/entrypoint.sh index 29c0dbb..3ea167d 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -7,4 +7,4 @@ sed -i "s|__ROUTE_PREFIX__|${ROUTE_PREFIX}|g" ./frontend/dist/static/env.js sed -i "s|href=\"/|href=\"${ROUTE_PREFIX}/|g" ./frontend/dist/index.html sed -i "s|src=\"/|src=\"${ROUTE_PREFIX}/|g" ./frontend/dist/index.html -exec python -m capella_model_explorer.backend ${MODEL_ENTRYPOINT} /views \ No newline at end of file +exec python -m capella_model_explorer.backend ${MODEL_ENTRYPOINT} /views diff --git a/frontend/index.html b/frontend/index.html index aa9c08b..cbe16b5 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -3,20 +3,17 @@ ~ SPDX-License-Identifier: Apache-2.0 --> - + - - - - - Model Explorer - - -
- - - + + + + + Model Explorer + + +
+ + + diff --git a/frontend/package.json b/frontend/package.json index 5c348b2..a79afc5 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -2,7 +2,6 @@ "name": "frontend", "private": true, "version": "0.0.0", - "type": "module", "scripts": { "dev": "vite", "build": "vite build", @@ -12,9 +11,13 @@ "build-storybook": "storybook build" }, "dependencies": { + "lucide-react": "^0.372.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-zoom-pan-pinch": "^3.4.3" + "react-modal": "^3.16.1", + "react-responsive": "^10.0.0", + "react-zoom-pan-pinch": "^3.4.3", + "tailwind-scrollbar": "^3.1.0" }, "devDependencies": { "@storybook/addon-essentials": "^7.6.16", @@ -37,9 +40,10 @@ "eslint-plugin-react-refresh": "^0.4.5", "eslint-plugin-storybook": "^0.8.0", "postcss": "^8.4.35", + "prettier": "^3.2.5", + "prettier-plugin-tailwindcss": "^0.5.14", "prop-types": "^15.8.1", "react-router-dom": "^6.22.2", - "react-responsive": "^10.0.0", "storybook": "^7.6.16", "tailwindcss": "^3.4.1", "vite": "^5.1.4", diff --git a/frontend/src/App.css b/frontend/src/App.css index 0cc3c92..cb5363c 100644 --- a/frontend/src/App.css +++ b/frontend/src/App.css @@ -16,7 +16,7 @@ transition: filter 300ms; } .logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); + filter: drop-shadow(0 0 2em #646cff); } .logo.react:hover { filter: drop-shadow(0 0 2em #61dafbaa); diff --git a/frontend/src/components/Breadcrumbs.jsx b/frontend/src/components/Breadcrumbs.jsx index 51516d7..0a1bf12 100644 --- a/frontend/src/components/Breadcrumbs.jsx +++ b/frontend/src/components/Breadcrumbs.jsx @@ -1,14 +1,14 @@ // Copyright DB InfraGO AG and contributors // SPDX-License-Identifier: Apache-2.0 -import React, { useEffect, useState } from 'react'; -import { Link, useLocation } from 'react-router-dom'; -import { API_BASE_URL } from '../APIConfig'; +import React, { useEffect, useState } from "react"; +import { Link, useLocation } from "react-router-dom"; +import { API_BASE_URL } from "../APIConfig"; export const Breadcrumbs = () => { const location = useLocation(); const [breadcrumbLabels, setBreadcrumbLabels] = useState({}); - const pathnames = location.pathname.split('/').filter(x => x); + const pathnames = location.pathname.split("/").filter((x) => x); const [error, setError] = useState(null); const fetchModelInfo = async () => { @@ -23,9 +23,9 @@ export const Breadcrumbs = () => { const viewsDict = await response.json(); const allViews = Object.values(viewsDict).flat(); - const view = allViews.find(v => v.idx.toString() === idx); + const view = allViews.find((v) => v.idx.toString() === idx); return view ? view.name : idx; -}; + }; // Function to fetch object names const fetchObjectName = async (uuid) => { @@ -37,10 +37,10 @@ export const Breadcrumbs = () => { useEffect(() => { const updateLabels = async () => { const title = await fetchModelInfo(); - const labels = { '/': title }; + const labels = { "/": title }; for (let i = 0; i < pathnames.length; i++) { - const to = `/${pathnames.slice(0, i + 1).join('/')}`; + const to = `/${pathnames.slice(0, i + 1).join("/")}`; if (i === 0) { labels[to] = await fetchViewName(pathnames[i]); @@ -58,24 +58,30 @@ export const Breadcrumbs = () => { updateLabels(); }, [location]); - const visible_pathnames = [breadcrumbLabels['/'], ...location.pathname.split('/').filter(x => x)]; + const visible_pathnames = [ + breadcrumbLabels["/"], + ...location.pathname.split("/").filter((x) => x), + ]; return ( -