Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
ad47d4a
fix: robocop pip check
marcdavidsut Feb 10, 2026
c063018
fix: paths to resources in extension README.md
marcdavidsut Feb 10, 2026
a7111bc
fix: folder roboview not found in pyproject.toml
marcdavidsut Feb 10, 2026
38279fa
Merge pull request #3 from viadee/fix/roboview-pip-check
jublankeviadee Feb 11, 2026
49a34a1
feat: add new logo
marcdavidsut Feb 12, 2026
927e979
fix: link to github repo
marcdavidsut Feb 12, 2026
8a81a7a
fix: images not visible in vscode marketplace
marcdavidsut Feb 12, 2026
930270a
chore: add to panel
marcdavidsut Feb 17, 2026
0c9abd0
chore: remove unused resources
marcdavidsut Feb 17, 2026
bd14804
chore: add out/ and .vsix to .gitignore
marcdavidsut Feb 17, 2026
3d589b6
Merge pull request #7 from viadee/feat/new-logo
jublankeviadee Feb 18, 2026
2a38d7e
fix: filename-overwrite
marcdavidsut Feb 18, 2026
c433c8c
Merge pull request #8 from viadee/fix/filename-overwrite
jublankeviadee Feb 19, 2026
ccd6557
fix: added suite setup/teardown to model visitor for called keyword p…
jublankeviadee Feb 23, 2026
8a8e9d5
misc: ruff corrections
jublankeviadee Feb 23, 2026
4c2240b
misc: ruff corrections
jublankeviadee Feb 23, 2026
3d99cfe
chore: refactor webviews using shadcn components
marcdavidsut Feb 23, 2026
c162b7d
chore: remove old components
marcdavidsut Feb 23, 2026
089a10e
chore: adapt styling
marcdavidsut Feb 24, 2026
811ff08
fix: update main-content panels to handle empty search results
marcdavidsut Feb 24, 2026
5fc8467
chore: add new sorting options and increase sorting selection size
marcdavidsut Feb 24, 2026
209aa50
chore: add hover-card for keyword similarity
marcdavidsut Feb 24, 2026
68c997d
chore: update details panels to use collapsible sections and styling
marcdavidsut Feb 24, 2026
bff9c3f
chore: move app/shared into components folder
marcdavidsut Feb 24, 2026
f83c266
chore: update screenshots
marcdavidsut Feb 24, 2026
8302030
Merge pull request #9 from viadee/Fix/include-suite-setup-and-teardown
marcdavidsut Feb 24, 2026
4d379c9
Merge pull request #10 from viadee/chore/webviews-with-shadcn
jublankeviadee Feb 24, 2026
3663556
chore: migrate to robocop version 8.2.2
marcdavidsut Mar 2, 2026
4fe584e
chore: add support for additional libraries
marcdavidsut Mar 2, 2026
35798ab
chore: add support for additional libraries
marcdavidsut Mar 2, 2026
56160b8
chore: refactor keyword similarity calculation with collections
marcdavidsut Mar 2, 2026
1c6157c
chore: update dependencies
marcdavidsut Mar 2, 2026
8c00d35
chore: update server port
marcdavidsut Mar 2, 2026
5b174d9
chore: update readme
marcdavidsut Mar 2, 2026
d388de7
Merge pull request #12 from viadee/chore/update-dependencies
jublankeviadee Mar 2, 2026
3ab41e3
Merge remote-tracking branch 'origin/main' into chore/publish_adjustm…
jublankeviadee Mar 2, 2026
7ffb01d
chore: publishing adjustments
jublankeviadee Mar 2, 2026
48fc1b8
chore: updated CHANGELOG.md
jublankeviadee Mar 2, 2026
8390543
Merge pull request #13 from viadee/chore/publish_adjustments
jublankeviadee Mar 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ __pycache__/

# Distribution / packaging
.Python
out/
build/
*.vsix
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
Expand Down
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,21 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how

## [Unreleased]

- Initial release
- Initial release

## [0.0.3] - 2026-03-02
### Added
- Fixed suite setup and teardown keywords are now included correctly
- Refactored existing webviews using Shadcn components and applied several visual improvements including:
- Added collapsible sections across all three webviews
- Adjusted font and badge colors
- Implemented table pagination in the main content area
- Ensured VS Code theme compatibility
- Added several tooltips for more information
- Several maintenance improvements and internal enhancements to keep the extension up to date.
- Updated README
- Updated server port from 8000 to 18123 (less used than 8000)
- Updated project dependencies to latest versions
- Refactored keyword similarity without numpy and scikit-learn (backend size is now just around 20 MB instead of 300MB before)
- Added support for additional libraries including all BuiltIn libraries (Collections, DateTime etc.), Appium and Requests
- Migrated to Robocop v8.2.2 (code changes were necessary)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ The **KPIs** section summarizes the most important metrics of your test suite:
- <strong>Global Filter:</strong> Jump directly to common problem areas across the entire project:
- <strong>Keywords without Documentation:</strong> Keywords that are missing documentation.
- <strong>Unused Keywords:</strong> Keywords that are never called in any analyzed file.
- <strong>Keywords with Calling Cycles:</strong> Keywords that participate in cyclic calls (A calls B, B calls A, etc.), which can indicate design or maintainability issues.
- <strong>Potential Keyword Duplicates:</strong> Keywords that may duplicate or closely resemble existing keywords.

<br>

Expand Down
1,296 changes: 704 additions & 592 deletions packages/roboview/poetry.lock

Large diffs are not rendered by default.

35 changes: 18 additions & 17 deletions packages/roboview/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,38 +1,39 @@
[tool.poetry]
name = "robotframework-roboview"
version = "0.0.2"
version = "0.0.3"
description = "RoboView is a Visual Studio Code extension designed to help you manage keywords within your Robot Framework projects and improve overall test quality through built-in Robocop integration. Its primary goal is to provide a comprehensive overview of all keywords and their relationships, making it easier to understand and maintain your test automation codebase."
license = "Apache 2.0"
authors = ["viadee Unternehmensberatung AG"]
readme = "README.md"

packages = [
{ include = "roboview" }
{ include = "roboview" }
]

[tool.poetry.dependencies]
python = ">=3.10,<3.14"
robotframework = "^7.2.2"
fastapi = "^0.115.8"
uvicorn = "^0.34.0"
pygments = "^2.19.1"
scikit-learn = "^1.6.1"
numpy = "^2.2.4"
pydantic = "^2.11.4"
starlette = "^0.46.0"
pydantic-settings = "^2.12.0"
python = ">=3.10,<=3.14"
robotframework = "^7.4.1"
fastapi = "^0.135.1"
uvicorn = "^0.41.0"
pygments = "^2.19.2"
pydantic = "^2.12.5"
starlette = "^0.52.1"
pydantic-settings = "^2.13.1"
coloredlogs = "^15.0.1"
robotframework-robocop = "^7.2.0"
robotframework-robocop = "^8.2.2"
httpx = "^0.28.1"
robotframework-browser = "^19.12.4"
robotframework-databaselibrary = "^2.4.1"
robotframework-crypto = "^0.4.2"
robotframework-seleniumlibrary = "^6.8.0"
typer = "^0.24.1"

[tool.poetry.group.dev.dependencies]
pyright = "^1.1.408"
pytest = "^9.0.2"
deptry = "^0.24.0"
robotframework-browser = "^19.12.5"
robotframework-databaselibrary = "^2.4.1"
robotframework-crypto = "^0.4.2"
robotframework-seleniumlibrary = "^6.8.0"
robotframework-appiumlibrary = "^3.2.1"
robotframework-requests = "^0.9.7"

[build-system]
requires = ["poetry-core"]
Expand Down
2 changes: 1 addition & 1 deletion packages/roboview/roboview/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,6 @@ async def catch_exceptions_middleware(request: Request, call_next: Callable) ->
uvicorn.run(
app,
host="127.0.0.1",
port=8000,
port=18123,
log_level=settings.LOG_LEVEL.lower(),
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from robot.parsing.model.statements import (
KeywordCall,
Setup,
SuiteSetup,
SuiteTeardown,
Teardown,
TestSetup,
TestTeardown,
Expand Down Expand Up @@ -51,6 +53,24 @@ def visit_KeywordCall(self, node: KeywordCall) -> None: # noqa: N802
"""
self._add_keyword(node.keyword)

def visit_SuiteSetup(self, node: SuiteSetup) -> None: # noqa: N802
"""Visit a SuiteSetup node and extract the keyword.

Arguments:
node (SuiteSetup): SuiteSetup node in the AST.

"""
self._add_keyword(node.name)

def visit_SuiteTeardown(self, node: SuiteTeardown) -> None: # noqa: N802
"""Visit a SuiteTeardown node and extract the keyword.

Arguments:
node (SuiteTeardown): SuiteTeardown node in the AST.

"""
self._add_keyword(node.name)

def visit_Setup(self, node: Setup) -> None: # noqa: N802
"""Visit a Setup node and extract the keyword.

Expand Down
2 changes: 1 addition & 1 deletion packages/roboview/roboview/registries/file_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def register(self, file: FileProperties) -> None:

"""
try:
self._file_registry[file.file_name] = file
self._file_registry[file.path] = file

except Exception:
logger.exception("Failed to register file: %s", file.path)
Expand Down
22 changes: 19 additions & 3 deletions packages/roboview/roboview/schemas/domain/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,29 @@
from enum import Enum


class LibraryType(Enum):
"""Supported Robot Framework libraries."""
class ExternalLibraryType(Enum):
"""Supported external Robot Framework libraries."""

BROWSER = "Browser"
SELENIUM = "SeleniumLibrary"
BUILTIN = "BuiltIn"
DATABASE = "DatabaseLibrary"
APPIUM = "AppiumLibrary"
REQUESTS = "RequestsLibrary"


class BuiltinLibraryType(Enum):
"""Supported Robot Framework BuiltIn libraries."""

BUILTIN = "BuiltIn"
COLLECTIONS = "Collections"
DATETIME = "DateTime"
DIALOGS = "Dialogs"
OPERATINGSYSTEM = "OperatingSystem"
PROCESS = "Process"
SCREENSHOT = "Screenshot"
STRING = "String"
TELNET = "Telnet"
XML = "XML"


class FileType(Enum):
Expand Down
69 changes: 57 additions & 12 deletions packages/roboview/roboview/services/keyword_register_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import logging
from pathlib import Path

from robot.errors import DataError
from robot.libdocpkg import LibraryDocumentation
from robot.parsing import get_model, get_resource_model
from roboview.models.robot_parsing.keyword_dependency_parsing import KeywordDependencyFinder
from roboview.models.robot_parsing.local_keyword_parsing import LocalKeywordFinder
from roboview.registries.keyword_registry import KeywordRegistry
from roboview.schemas.domain.common import FileType, LibraryType
from roboview.schemas.domain.common import BuiltinLibraryType, ExternalLibraryType, FileType
from roboview.schemas.domain.keywords import KeywordProperties
from roboview.utils.directory_parsing import DirectoryParser

Expand Down Expand Up @@ -45,16 +46,33 @@ def initialize(self) -> None:

This method:
1. Loads local keywords from .robot and .resource files
2. Loads external library keywords (Browser, Selenium, Database, BuiltIn)
3. Populates the KeywordRegistry with all discovered keywords
2. Loads built-in library keywords (BuiltIn, Collections, DateTime, etc.)
3. Loads external library keywords (Browser, Selenium, Database, Appium, Requests) if installed
4. Populates the KeywordRegistry with all discovered keywords

"""
try:
logger.info("Register user-defined keywords")
self._load_local_keywords()
self._load_library_keywords()
logger.info("Registry initialized with %d keywords", len(self.registry))
logger.info("Finished registering user-defined keywords")
except Exception:
logger.exception("Failed to initialize keyword registry")
logger.exception("Failed to register keywords with user-defined keywords")

try:
logger.info("Register built-in library keywords")
self._load_builtin_library_keywords()
logger.info("Finished registering built-in library keywords")
except Exception:
logger.exception("Failed to register keywords with built-in keywords")

try:
logger.info("Register external library keywords")
self._load_external_library_keywords()
logger.info("Finished registering external library keywords")
except Exception:
logger.exception("Failed to register keywords with external keywords")

logger.info("Registry initialized with %d keywords", len(self.registry))

def _load_local_keywords(self) -> None:
"""Load local keywords from Robot Framework files."""
Expand Down Expand Up @@ -125,13 +143,37 @@ def _enrich_with_called_keywords(
keyword_doc.called_keywords = dependency_map.get(keyword_name, [])
return keyword_doc

def _load_library_keywords(self) -> None:
def _load_builtin_library_keywords(self) -> None:
libraries = [
BuiltinLibraryType.BUILTIN,
BuiltinLibraryType.COLLECTIONS,
BuiltinLibraryType.DATETIME,
BuiltinLibraryType.DIALOGS,
BuiltinLibraryType.OPERATINGSYSTEM,
BuiltinLibraryType.PROCESS,
BuiltinLibraryType.SCREENSHOT,
BuiltinLibraryType.STRING,
BuiltinLibraryType.TELNET,
BuiltinLibraryType.XML,
]

for library_type in libraries:
try:
keyword_doc = self._get_library_keywords(library_type)
for keyword in keyword_doc:
self.registry.register(keyword)
except Exception:
logger.exception("Failed to load library: %s", library_type.value)
continue

def _load_external_library_keywords(self) -> None:
"""Load keywords from external Robot Framework libraries."""
libraries = [
LibraryType.BROWSER,
LibraryType.SELENIUM,
LibraryType.DATABASE,
LibraryType.BUILTIN,
ExternalLibraryType.BROWSER,
ExternalLibraryType.SELENIUM,
ExternalLibraryType.APPIUM,
ExternalLibraryType.DATABASE,
ExternalLibraryType.REQUESTS,
]

for library_type in libraries:
Expand All @@ -145,7 +187,7 @@ def _load_library_keywords(self) -> None:
continue

@staticmethod
def _get_library_keywords(library_type: LibraryType) -> list[KeywordProperties]:
def _get_library_keywords(library_type: BuiltinLibraryType | ExternalLibraryType) -> list[KeywordProperties]:
"""Get keyword metadata for a specific library.

Arguments:
Expand Down Expand Up @@ -176,6 +218,9 @@ def _get_library_keywords(library_type: LibraryType) -> list[KeywordProperties]:
validation_str_with_prefix=str(keyword_with_prefix).lower().replace(" ", "").replace("_", ""),
)
)
except DataError:
logger.warning("Library not installed: %s will be skipped", library_type.value)
return []

except Exception:
logger.exception("Library %s could not be loaded", lib_name)
Expand Down
Loading