diff --git a/services/api-server/src/api_server/html5.py b/services/api-server/src/api_server/html5.py index 9f9f3e1..aedc05a 100644 --- a/services/api-server/src/api_server/html5.py +++ b/services/api-server/src/api_server/html5.py @@ -323,6 +323,7 @@ def render_html5_object_context( access: object | None = None, ui: object | None = None, runtime: Iterable[object] | None = None, + knowledge: Iterable[object] | None = None, ) -> str: if schema is None or impact is None: return f""" @@ -343,6 +344,7 @@ def render_html5_object_context( grants = getattr(access, "grants", []) if access is not None else [] ui_forms = getattr(ui, "forms", []) if ui is not None else [] runtime_items = list(runtime or []) + knowledge_items = list(knowledge or []) return f"""
Object context
@@ -358,6 +360,7 @@ def render_html5_object_context( {_metric("Forms", len(ui_forms) or len(forms))} {_metric("Roles", len(grants) or len(roles))} {_metric("Runtime", len(runtime_items))} + {_metric("Knowledge", len(knowledge_items))}
{''.join(_named_node_item("attr", item) for item in attributes[:6]) or '

Реквизиты не найдены

'} @@ -365,6 +368,7 @@ def render_html5_object_context( {''.join(_ui_form_item(item) for item in ui_forms[:4])} {''.join(_role_access_item(item) for item in grants[:6])} {''.join(_runtime_summary_item(item) for item in runtime_items[:6])} + {''.join(_knowledge_record_item(item) for item in knowledge_items[:6])} {''.join(_named_node_item("routine", item) for item in routines[:6])} {''.join(_named_node_item("job", item) for item in jobs[:4])}
@@ -1442,6 +1446,19 @@ def _runtime_summary_item(item: object) -> str: """ +def _knowledge_record_item(record: object) -> str: + title = str(getattr(record, "title", "knowledge")) + scope = _enum_text(getattr(record, "scope", "")) + body = str(getattr(record, "body", "") or "") + record_id = str(getattr(record, "record_id", "")) + return f""" +
+ {escape(title)} + {escape(scope)} · {escape(record_id)} · {escape(body[:120])} +
+ """ + + def _authoring_diff_item(line: object) -> str: kind = str(getattr(line, "kind", "")) text = str(getattr(line, "text", "")) diff --git a/services/api-server/src/api_server/main.py b/services/api-server/src/api_server/main.py index d1abfd7..1f5e9d3 100644 --- a/services/api-server/src/api_server/main.py +++ b/services/api-server/src/api_server/main.py @@ -1748,8 +1748,9 @@ async def html5_project_object_context(project_id: str, object_name: str) -> Res access = await get_object_access(project_id, object_name) ui = await get_object_ui(project_id, object_name) runtime = _runtime_for_object_context(project_id, impact) + knowledge = _knowledge_for_object_context(schema, impact, ui) return Response( - render_html5_object_context(project_id, schema, impact, access, ui, runtime), + render_html5_object_context(project_id, schema, impact, access, ui, runtime, knowledge), media_type="text/html; charset=utf-8", ) @@ -8142,6 +8143,40 @@ def _runtime_for_object_context(project_id: str, impact: ObjectImpactResponse) - ] +def _knowledge_for_object_context( + schema: ObjectSchemaResponse, + impact: ObjectImpactResponse, + ui: ObjectUiResponse, +) -> list[KnowledgeRecord]: + lineages: set[str] = {schema.object.lineage_id, impact.object.lineage_id} + lineages.update(item.lineage_id for item in schema.attributes) + for section in schema.tabular_sections: + lineages.add(section.tabular_section.lineage_id) + lineages.update(column.lineage_id for column in section.columns) + for group in [ + impact.modules, + impact.routines, + impact.forms, + impact.commands, + impact.roles, + impact.jobs, + impact.writes, + impact.query_tables, + ]: + lineages.update(item.lineage_id for item in group) + for form in ui.forms: + lineages.add(form.form.lineage_id) + lineages.update(command.lineage_id for command in form.commands) + lineages.update(element.lineage_id for element in form.elements) + lineages.update(handler.lineage_id for handler in form.command_handlers.values()) + records = [ + record + for record in _knowledge.list_records() + if lineages.intersection(record.related_lineages) + ] + return sorted(records, key=lambda item: item.title.lower())[:12] + + def _current_import_source(project_id: str) -> ImportSourceKind: setup = _project_setup_response(project_id) if setup.current_source is not None: diff --git a/services/api-server/tests/test_api.py b/services/api-server/tests/test_api.py index db4c130..0531a8d 100644 --- a/services/api-server/tests/test_api.py +++ b/services/api-server/tests/test_api.py @@ -268,6 +268,17 @@ def test_html5_object_context_fragment(tmp_path: Path): }, ) assert signal.status_code == 200 + knowledge = client.post( + "/knowledge", + json={ + "record_id": f"knowledge.html5.object.{uuid4()}", + "scope": "PROJECT", + "title": "Правила проведения HTML5", + "body": "Контекст проведения заказа для HTML5 inspector.", + "related_lineages": [handler["lineage_id"]], + }, + ) + assert knowledge.status_code == 200 editor = client.get(f"/html5/projects/{project_id}/editor") assert editor.status_code == 200 @@ -288,6 +299,8 @@ def test_html5_object_context_fragment(tmp_path: Path): assert "1 signals" in context.text assert "1 errors" in context.text assert "125.0 ms" in context.text + assert "Правила проведения HTML5" in context.text + assert "Контекст проведения заказа" in context.text assert "Роль.Менеджер" in context.text assert "read, write, post" in context.text or "post, read, write" in context.text assert "