Skip to content

Commit

Permalink
Merge pull request strictdoc-project#1854 from strictdoc-project/stan…
Browse files Browse the repository at this point in the history
…islaw/delete_section_confirmation_before_and_after

UI: Create node: parse, validate, and render LINK/ANCHOR
  • Loading branch information
stanislaw authored Jun 6, 2024
2 parents ea37698 + 6f2be17 commit 67edeca
Show file tree
Hide file tree
Showing 53 changed files with 411 additions and 19 deletions.
12 changes: 11 additions & 1 deletion strictdoc/core/traceability_index_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,17 @@ def create_from_document_tree(
f"{part.link}."
)
traceability_index.create_inline_link(part)

elif isinstance(part, Anchor):
graph_database.create_link(
link_type=GraphLinkType.MID_TO_NODE,
lhs_node=part.mid,
rhs_node=part,
)
graph_database.create_link(
link_type=GraphLinkType.UID_TO_NODE,
lhs_node=part.value,
rhs_node=part,
)
if requirement.reserved_uid is None:
continue

Expand Down
23 changes: 21 additions & 2 deletions strictdoc/core/transforms/create_requirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ def perform(self):
get_textx_syntax_error_message(exception)
)
if len(errors) > 0:
raise validation_error
for field_name_, field_errors_ in validation_error.errors.items():
for field_error_ in field_errors_:
form_object.add_error(field_name_, field_error_)
return

if whereto == NodeCreationOrder.CHILD:
parent = reference_node
Expand Down Expand Up @@ -225,12 +228,16 @@ def perform(self):
if free_text_content is not None
else None
)

requirement.set_field_value(
field_name=form_field_name,
form_field_index=form_field_index,
value=requirement_field,
)
if free_text_content is not None:
for part_ in requirement_field.parts:
if isinstance(part_, str):
continue
part_.parent = requirement_field

requirement.reserved_mid = MID(form_object.requirement_mid)
if document.config.enable_mid:
Expand Down Expand Up @@ -263,4 +270,16 @@ def perform(self):
# FIXME
pass

for free_text_container_ in map_form_to_requirement_fields.values():
if free_text_container_ is None:
continue
for part in free_text_container_.parts:
if isinstance(part, Anchor):
# Since this is a new section, we just need to register the
# new anchor. By this time, we know that there is no
# existing anchor with this name.
traceability_index.update_with_anchor(part)
elif isinstance(part, InlineLink):
traceability_index.create_inline_link(part)

traceability_index.update_last_updated()
7 changes: 4 additions & 3 deletions strictdoc/core/transforms/validation_error.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from dataclasses import dataclass
from typing import Dict, List


Expand All @@ -12,7 +13,7 @@ def __init__(self, message: str, errors: List[str]):
self.errors: List[str] = errors


@dataclass
class MultipleValidationError(Exception):
def __init__(self, message: str, errors: Dict[str, List[str]]):
super().__init__(message)
self.errors: Dict[str, List[str]] = errors
message: str
errors: Dict[str, List[str]]
4 changes: 1 addition & 3 deletions strictdoc/helpers/string.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,4 @@ def create_safe_document_file_name(string) -> str:


def ensure_newline(text: str) -> str:
if not text.endswith("\n"):
text += "\n"
return text
return text.rstrip() + "\n"
21 changes: 11 additions & 10 deletions strictdoc/server/routers/main_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,17 @@ async def create_requirement(request: Request):
config=project_config,
)

if not form_object.any_errors():
command = CreateRequirementTransform(
form_object=form_object,
project_config=project_config,
whereto=whereto,
requirement_mid=requirement_mid,
reference_mid=reference_mid,
traceability_index=export_action.traceability_index,
)
command.perform()

if form_object.any_errors():
template = env().get_template(
"actions/"
Expand Down Expand Up @@ -924,16 +935,6 @@ async def create_requirement(request: Request):
},
)

transform = CreateRequirementTransform(
form_object=form_object,
project_config=project_config,
whereto=whereto,
requirement_mid=requirement_mid,
reference_mid=reference_mid,
traceability_index=export_action.traceability_index,
)
transform.perform()

# Saving new content to .SDoc files.
SDWriter().write_to_file(document)
if document != context_document:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[DOCUMENT]
TITLE: Document 1

[FREETEXT]
Hello world!
[/FREETEXT]

[REQUIREMENT]
STATEMENT: >>>
[ANCHOR: AD1]
<<<
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[DOCUMENT]
TITLE: Document 1

[FREETEXT]
Hello world!
[/FREETEXT]

[REQUIREMENT]
STATEMENT: >>>
[ANCHOR: AD1]
<<<
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from tests.end2end.e2e_case import E2ECase
from tests.end2end.end2end_test_setup import End2EndTestSetup
from tests.end2end.helpers.screens.document.form_edit_requirement import (
Form_EditRequirement,
)
from tests.end2end.helpers.screens.project_index.screen_project_index import (
Screen_ProjectIndex,
)
from tests.end2end.server import SDocTestServer


class Test(E2ECase):
def test(self):
test_setup = End2EndTestSetup(path_to_test_file=__file__)

with SDocTestServer(
input_path=test_setup.path_to_sandbox
) as test_server:
self.open(test_server.get_host_and_port())

screen_project_index = Screen_ProjectIndex(self)

screen_project_index.assert_on_screen()
screen_project_index.assert_contains_document("Document 1")

screen_document = screen_project_index.do_click_on_first_document()

screen_document.assert_on_screen_document()
screen_document.assert_header_document_title("Document 1")

screen_document.assert_text("Hello world!")

# Requirement 1
requirement1_node = screen_document.get_node(1)
root_node_menu = requirement1_node.do_open_node_menu()
form_edit_requirement: Form_EditRequirement = (
root_node_menu.do_node_add_requirement_below()
)
form_edit_requirement.do_fill_in_field_statement(
"""
[ANCHOR: AD1]
"""
)
form_edit_requirement.do_form_submit_and_catch_error(
"A node contains an anchor that already exists: AD1."
)

assert test_setup.compare_sandbox_and_expected_output()
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
from tests.end2end.e2e_case import E2ECase
from tests.end2end.end2end_test_setup import End2EndTestSetup
from tests.end2end.helpers.screens.document.form_edit_requirement import (
Form_EditRequirement,
)
from tests.end2end.helpers.screens.project_index.screen_project_index import (
Screen_ProjectIndex,
)
from tests.end2end.server import SDocTestServer


class Test(E2ECase):
def test(self):
test_setup = End2EndTestSetup(path_to_test_file=__file__)

with SDocTestServer(
input_path=test_setup.path_to_sandbox
) as test_server:
self.open(test_server.get_host_and_port())

screen_project_index = Screen_ProjectIndex(self)

screen_project_index.assert_on_screen()
screen_project_index.assert_contains_document("Document 1")

screen_document = screen_project_index.do_click_on_first_document()

screen_document.assert_on_screen_document()
screen_document.assert_header_document_title("Document 1")

screen_document.assert_text("Hello world!")

# Requirement 1
root_node = screen_document.get_root_node()
root_node_menu = root_node.do_open_node_menu()
form_edit_requirement: Form_EditRequirement = (
root_node_menu.do_node_add_requirement_first()
)
form_edit_requirement.do_fill_in_field_uid("REQ-1")
form_edit_requirement.do_fill_in_field_title("Req #1")
form_edit_requirement.do_fill_in_field_statement(
"""\
Modified statement.
[ANCHOR: AD1]!!!GARBAGE!!!
"""
)
form_edit_requirement.do_form_submit_and_catch_error(
"SDoc markup error: NCHOR: AD1*]!!!GARBAG."
)

assert test_setup.compare_sandbox_and_expected_output()
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[DOCUMENT]
TITLE: Document 1

[FREETEXT]
Hello world!
[/FREETEXT]

[REQUIREMENT]
UID: REQ-1
TITLE: Req #1
STATEMENT: Req #1 statement.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from tests.end2end.e2e_case import E2ECase
from tests.end2end.end2end_test_setup import End2EndTestSetup
from tests.end2end.helpers.screens.document.form_edit_requirement import (
Form_EditRequirement,
)
from tests.end2end.helpers.screens.project_index.screen_project_index import (
Screen_ProjectIndex,
)
from tests.end2end.server import SDocTestServer


class Test(E2ECase):
def test(self):
test_setup = End2EndTestSetup(path_to_test_file=__file__)

with SDocTestServer(
input_path=test_setup.path_to_sandbox
) as test_server:
self.open(test_server.get_host_and_port())

screen_project_index = Screen_ProjectIndex(self)

screen_project_index.assert_on_screen()
screen_project_index.assert_contains_document("Document 1")

screen_document = screen_project_index.do_click_on_first_document()

screen_document.assert_on_screen_document()
screen_document.assert_header_document_title("Document 1")

screen_document.assert_text("Hello world!")

# Requirement 1
root_node = screen_document.get_node(1)
root_node_menu = root_node.do_open_node_menu()
form_edit_requirement: Form_EditRequirement = (
root_node_menu.do_node_add_requirement_below()
)
form_edit_requirement.do_fill_in_field_uid("REQ-2")
form_edit_requirement.do_fill_in_field_title("Req #2")
form_edit_requirement.do_fill_in_field_statement(
"See [LINK: THIS-DOES-NOT-EXIST]."
)
form_edit_requirement.do_form_submit_and_catch_error(
"A LINK points to a node that does not exist: 'THIS-DOES-NOT-EXIST'."
)

assert test_setup.compare_sandbox_and_expected_output()
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from tests.end2end.e2e_case import E2ECase
from tests.end2end.end2end_test_setup import End2EndTestSetup
from tests.end2end.helpers.screens.document.form_edit_requirement import (
Form_EditRequirement,
)
from tests.end2end.helpers.screens.project_index.screen_project_index import (
Screen_ProjectIndex,
)
from tests.end2end.server import SDocTestServer


class Test(E2ECase):
def test(self):
test_setup = End2EndTestSetup(path_to_test_file=__file__)

with SDocTestServer(
input_path=test_setup.path_to_sandbox
) as test_server:
self.open(test_server.get_host_and_port())

screen_project_index = Screen_ProjectIndex(self)

screen_project_index.assert_on_screen()
screen_project_index.assert_contains_document("Document 1")

screen_document = screen_project_index.do_click_on_first_document()

screen_document.assert_on_screen_document()
screen_document.assert_header_document_title("Document 1")

screen_document.assert_text("Hello world!")

# Requirement 1
root_node = screen_document.get_root_node()
root_node_menu = root_node.do_open_node_menu()
form_edit_requirement: Form_EditRequirement = (
root_node_menu.do_node_add_requirement_first()
)
form_edit_requirement.do_fill_in_field_uid("REQ-1")
form_edit_requirement.do_fill_in_field_title("Req #1")
form_edit_requirement.do_fill_in_field_statement(
"[ANCHOR: ANC-1, Anchor title]"
"""
Modified free text!
[ANCHOR: AD1]
[ANCHOR: AD1]
"""
)
form_edit_requirement.do_form_submit_and_catch_error(
"A node cannot have two anchors with the same identifier: AD1."
)

assert test_setup.compare_sandbox_and_expected_output()
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[DOCUMENT]
TITLE: Document 1

[FREETEXT]
Hello world!
[/FREETEXT]

[REQUIREMENT]
UID: REQ-1
TITLE: Req #1
STATEMENT: >>>
[ANCHOR: ANC-1, Anchor title]
<<<

[REQUIREMENT]
UID: REQ-2
TITLE: Req #2
STATEMENT: >>>
See [LINK: ANC-1].
<<<
Loading

0 comments on commit 67edeca

Please sign in to comment.