Skip to content

Commit 3dbc75d

Browse files
authored
Merge pull request #14 from viadee/feat/visual-editor-docker-staleness
v0.7.0: Docker UX, branch switching, run cancel, 136 new tests
2 parents 3b89247 + 24ea241 commit 3dbc75d

65 files changed

Lines changed: 5566 additions & 648 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
11
# Changelog
22

3+
## [0.7.0] - 2026-03-12
4+
5+
### Features
6+
- **RobotEditor Visual Improvements** — Section colors, variable highlighting, expand/collapse, lazy keyword loading, vertical args overflow
7+
- **Docker Error Handling**`DockerNotAvailableError`, `DockerImageNotFoundError` with translated error banners
8+
- **Docker Image Staleness Detection**`docker_image_built_at`, `packages_changed_at`, computed `docker_image_stale`, amber warnings in Execution + Explorer views
9+
- **Persistent Docker Build Status**`docker_build_status`/`docker_build_error` on Environment model, server-driven UI
10+
- **Docker Build Terminal Output** — WebSocket-streamed live build logs with terminal component (pulsing dot, auto-scroll, show/hide toggle)
11+
- **Docker Build Robustness** — Playwright base image, pre-build disk space check, large base image hint, dangling image cleanup, enriched Docker error messages
12+
- **Execution View** — Project name column in runs table and detail panel, duration column
13+
- **rfbrowser Init Visibility** — Post-install node_modules verification, pre-run Browser lib check, "initializing" UI status
14+
- **Run Cancellation** — Actually kills spawned subprocess via runner registry pattern; status check after execution prevents overwrite
15+
- **Branch Switching**`POST /repos/{id}/checkout` endpoint, branch dropdown on project cards
16+
- **Auto-Sync Toggle** — Checkbox on project cards to enable/disable periodic Git sync
17+
18+
### Fixes
19+
- **Report Tree** — Fix `.//tag` XPath finding keyword descendant tags as test tags (now `tags/tag`); fix CSS connector lines (`:first-child``:last-child`)
20+
- **Explorer Editor Chain** — Fix v-if/v-else-if chain where no-environment banner blocked RobotEditor from rendering
21+
- **Startup Cleanup** — Reset stuck `docker_build_status=building``error` and stuck packages on app start
22+
23+
### Tests
24+
- 136 new backend tests (656 → 792 total) covering previously untested modules:
25+
- `task_executor.py` (15 tests), `ai/encryption.py` (15 tests), `ai/llm_client.py` (35 tests)
26+
- `websocket/manager.py` (42 tests), `execution/tasks.py` (21 tests)
27+
- `repos/service.py` branch functions (8 tests), `repos/router.py` checkout endpoints (13 tests)
28+
- All 267 E2E tests passing
29+
30+
### Docs
31+
- In-app documentation updated for Docker build terminal, image staleness, branch switching, auto-sync, run cancellation, rfbrowser init (EN/DE/FR/ES)
32+
333
## [0.6.0] - 2026-03-11
434

535
### Features
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
*** Test Cases ***
3+
Mein Testfall 1
4+
Log Hallo ihr Hübschen
5+
blabla
6+
Fatal Error FEHLER LALA
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
*** Settings ***
3+
Library Browser
4+
5+
*** Test Cases ***
6+
Beispiel 1
7+
New Page https://example.cypress.io
8+
Click "type"
9+
Get Url *= /commands/actions
10+
Type Text .action-email fake@email.com
11+
Get Text .action-email == fake@email.com
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
version: "2"
2+
metadata:
3+
title: "Basic Arithmetic Operations Tests"
4+
author: ""
5+
created: "2022-03-10"
6+
last_generated: null
7+
generation_hash: null
8+
target_file: "basic_arithmetic_operations.robot"
9+
libraries:
10+
- String
11+
- Collections
12+
13+
test_sets:
14+
- name: "Arithmetic"
15+
description: "Tests for basic arithmetic operations."
16+
tags: [smoke, arithmetic]
17+
setup: null
18+
teardown: null
19+
test_cases:
20+
- name: "Addition Of Positive Numbers"
21+
description: "Verify that addition works for positive integers."
22+
priority: high
23+
steps:
24+
- "Evaluate 3 + 7"
25+
- "Should Be Equal As Numbers ${result} 10"
26+
- name: "Addition With Negative Numbers"
27+
description: "Verify addition with negative operands."
28+
priority: medium
29+
steps:
30+
- "Evaluate -5 + 3"
31+
- "Should Be Equal As Numbers ${result} -2"
32+
- "Evaluate -10 + (-20)"
33+
- "Should Be Equal As Numbers ${result2} -30"
34+
- name: "Subtraction"
35+
description: "Verify subtraction of integers."
36+
priority: medium
37+
steps:
38+
- "Evaluate 100 - 42"
39+
- "Should Be Equal As Numbers ${result} 58"
40+
- name: "Multiplication And Division"
41+
description: "Verify multiplication and division."
42+
priority: medium
43+
steps:
44+
- "Evaluate 6 * 7"
45+
- "Should Be Equal As Numbers ${product} 42"
46+
- "Evaluate 84 / 4"
47+
- "Should Be Equal As Numbers ${quotient} 21"
48+
- name: "Integer Division And Modulo"
49+
description: "Verify floor division and modulo operator."
50+
priority: medium
51+
steps:
52+
- "Evaluate 17 // 5"
53+
- "Should Be Equal As Numbers ${floor} 3"
54+
- "Evaluate 17 % 5"
55+
- "Should Be Equal As Numbers ${mod} 2"
56+
- name: "Floating Point Arithmetic"
57+
description: "Verify floating point calculations using PI."
58+
priority: medium
59+
tags: [arithmetic, float]
60+
steps:
61+
- "Evaluate 2 * ${PI} * 5"
62+
- "Should Be True abs(${circumference} - 31.4159) < 0.001"
63+
- "Evaluate ${PI} * 10**2"
64+
- "Should Be True abs(${area} - 314.159) < 0.001"
65+
- name: "Power And Square Root"
66+
description: "Verify exponentiation and square root."
67+
priority: medium
68+
steps:
69+
- "Evaluate 2 ** 10"
70+
- "Should Be Equal As Numbers ${power} 1024"
71+
- "Evaluate 144 ** 0.5"
72+
- "Should Be Equal As Numbers ${sqrt} 12"
73+
- name: "Comparison Operators"
74+
description: "Verify comparison expressions evaluate correctly."
75+
priority: high
76+
tags: [smoke, logic]
77+
steps:
78+
- "Should Be True 10 > 5"
79+
- "Should Be True 3 <= 3"
80+
- "Should Be True 7 != 8"
81+
- "Should Be True ${MAX_INT} == 9999"
82+
- name: "Chained Calculations"
83+
description: "Verify a multi-step calculation pipeline."
84+
priority: medium
85+
steps:
86+
- "Evaluate 10 + 20"
87+
- "Evaluate ${step1} * 3"
88+
- "Evaluate ${step2} - 10"
89+
- "Evaluate ${step3} / 8"
90+
- "Should Be Equal As Numbers ${step4} 10"
91+
- name: "Absolute Value And Rounding"
92+
description: "Verify abs() and round() built-in functions."
93+
priority: medium
94+
steps:
95+
- "Evaluate abs(-42)"
96+
- "Should Be Equal As Numbers ${abs_val} 42"
97+
- "Evaluate round(3.14159, 2)"
98+
- "Should Be Equal As Numbers ${rounded} 3.14"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""add docker_image_built_at and packages_changed_at to environments
2+
3+
Revision ID: 52b0837c0b7f
4+
Revises: 001_add_registry_urls
5+
Create Date: 2026-03-12 18:29:53.073916
6+
"""
7+
from typing import Sequence, Union
8+
9+
from alembic import op
10+
import sqlalchemy as sa
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision: str = '52b0837c0b7f'
15+
down_revision: Union[str, None] = '001_add_registry_urls'
16+
branch_labels: Union[str, Sequence[str], None] = None
17+
depends_on: Union[str, Sequence[str], None] = None
18+
19+
20+
def upgrade() -> None:
21+
with op.batch_alter_table('environments', schema=None) as batch_op:
22+
batch_op.add_column(sa.Column('docker_image_built_at', sa.DateTime(), nullable=True))
23+
batch_op.add_column(sa.Column('packages_changed_at', sa.DateTime(), nullable=True))
24+
25+
26+
def downgrade() -> None:
27+
with op.batch_alter_table('environments', schema=None) as batch_op:
28+
batch_op.drop_column('packages_changed_at')
29+
batch_op.drop_column('docker_image_built_at')
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"""add docker_build_status and docker_build_error to environments
2+
3+
Revision ID: 9bf996e4380f
4+
Revises: 52b0837c0b7f
5+
Create Date: 2026-03-12 19:09:21.463720
6+
"""
7+
from typing import Sequence, Union
8+
9+
from alembic import op
10+
import sqlalchemy as sa
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision: str = '9bf996e4380f'
15+
down_revision: Union[str, None] = '52b0837c0b7f'
16+
branch_labels: Union[str, Sequence[str], None] = None
17+
depends_on: Union[str, Sequence[str], None] = None
18+
19+
20+
def upgrade() -> None:
21+
# ### commands auto generated by Alembic - please adjust! ###
22+
op.drop_table('ai_jobs')
23+
op.drop_table('ai_providers')
24+
with op.batch_alter_table('environment_packages', schema=None) as batch_op:
25+
batch_op.alter_column('install_status',
26+
existing_type=sa.VARCHAR(length=20),
27+
nullable=False,
28+
existing_server_default=sa.text("'installed'"))
29+
30+
with op.batch_alter_table('environments', schema=None) as batch_op:
31+
batch_op.add_column(sa.Column('docker_build_status', sa.String(length=20), nullable=True))
32+
batch_op.add_column(sa.Column('docker_build_error', sa.Text(), nullable=True))
33+
34+
# ### end Alembic commands ###
35+
36+
37+
def downgrade() -> None:
38+
# ### commands auto generated by Alembic - please adjust! ###
39+
with op.batch_alter_table('environments', schema=None) as batch_op:
40+
batch_op.drop_column('docker_build_error')
41+
batch_op.drop_column('docker_build_status')
42+
43+
with op.batch_alter_table('environment_packages', schema=None) as batch_op:
44+
batch_op.alter_column('install_status',
45+
existing_type=sa.VARCHAR(length=20),
46+
nullable=True,
47+
existing_server_default=sa.text("'installed'"))
48+
49+
op.create_table('ai_providers',
50+
sa.Column('id', sa.INTEGER(), nullable=False),
51+
sa.Column('name', sa.VARCHAR(length=100), nullable=False),
52+
sa.Column('provider_type', sa.VARCHAR(length=50), nullable=False),
53+
sa.Column('api_base_url', sa.VARCHAR(length=500), nullable=True),
54+
sa.Column('api_key_encrypted', sa.TEXT(), nullable=True),
55+
sa.Column('model_name', sa.VARCHAR(length=100), nullable=False),
56+
sa.Column('temperature', sa.FLOAT(), nullable=False),
57+
sa.Column('max_tokens', sa.INTEGER(), nullable=False),
58+
sa.Column('is_default', sa.BOOLEAN(), nullable=False),
59+
sa.Column('created_by', sa.INTEGER(), nullable=False),
60+
sa.Column('created_at', sa.DATETIME(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False),
61+
sa.Column('updated_at', sa.DATETIME(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False),
62+
sa.ForeignKeyConstraint(['created_by'], ['users.id'], name=op.f('fk_ai_providers_created_by_users')),
63+
sa.PrimaryKeyConstraint('id', name=op.f('pk_ai_providers')),
64+
sa.UniqueConstraint('name', name=op.f('uq_ai_providers_name'))
65+
)
66+
op.create_table('ai_jobs',
67+
sa.Column('id', sa.INTEGER(), nullable=False),
68+
sa.Column('job_type', sa.VARCHAR(length=20), nullable=False),
69+
sa.Column('status', sa.VARCHAR(length=20), nullable=False),
70+
sa.Column('repository_id', sa.INTEGER(), nullable=False),
71+
sa.Column('provider_id', sa.INTEGER(), nullable=False),
72+
sa.Column('report_id', sa.INTEGER(), nullable=True),
73+
sa.Column('spec_path', sa.VARCHAR(length=500), nullable=False),
74+
sa.Column('target_path', sa.VARCHAR(length=500), nullable=True),
75+
sa.Column('result_preview', sa.TEXT(), nullable=True),
76+
sa.Column('error_message', sa.TEXT(), nullable=True),
77+
sa.Column('token_usage', sa.INTEGER(), nullable=True),
78+
sa.Column('triggered_by', sa.INTEGER(), nullable=False),
79+
sa.Column('started_at', sa.DATETIME(), nullable=True),
80+
sa.Column('completed_at', sa.DATETIME(), nullable=True),
81+
sa.Column('created_at', sa.DATETIME(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False),
82+
sa.Column('updated_at', sa.DATETIME(), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=False),
83+
sa.ForeignKeyConstraint(['provider_id'], ['ai_providers.id'], name=op.f('fk_ai_jobs_provider_id_ai_providers')),
84+
sa.ForeignKeyConstraint(['report_id'], ['reports.id'], name=op.f('fk_ai_jobs_report_id_reports')),
85+
sa.ForeignKeyConstraint(['repository_id'], ['repositories.id'], name=op.f('fk_ai_jobs_repository_id_repositories')),
86+
sa.ForeignKeyConstraint(['triggered_by'], ['users.id'], name=op.f('fk_ai_jobs_triggered_by_users')),
87+
sa.PrimaryKeyConstraint('id', name=op.f('pk_ai_jobs'))
88+
)
89+
# ### end Alembic commands ###
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""add docker_build_log to environments
2+
3+
Revision ID: a3c7e1f82d4b
4+
Revises: 9bf996e4380f
5+
Create Date: 2026-03-12 20:00:00.000000
6+
"""
7+
from typing import Sequence, Union
8+
9+
from alembic import op
10+
import sqlalchemy as sa
11+
12+
13+
# revision identifiers, used by Alembic.
14+
revision: str = 'a3c7e1f82d4b'
15+
down_revision: Union[str, None] = '9bf996e4380f'
16+
branch_labels: Union[str, Sequence[str], None] = None
17+
depends_on: Union[str, Sequence[str], None] = None
18+
19+
20+
def upgrade() -> None:
21+
op.add_column('environments', sa.Column('docker_build_log', sa.Text(), nullable=True))
22+
23+
24+
def downgrade() -> None:
25+
op.drop_column('environments', 'docker_build_log')

backend/pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ packages = ["src"]
77

88
[project]
99
name = "roboscope-backend"
10-
version = "0.6.0"
10+
version = "0.7.0"
1111
description = "RoboScope - Web-based Robot Framework Test Management Tool"
1212
requires-python = ">=3.11"
1313
dependencies = [
@@ -32,6 +32,8 @@ dependencies = [
3232
"httpx>=0.28.0",
3333
"slowapi>=0.1.9",
3434
"python-json-logger>=3.0.0",
35+
"rf-mcp>=0.30.0",
36+
"fastmcp<3",
3537
]
3638

3739
[project.optional-dependencies]

0 commit comments

Comments
 (0)