Skip to content

Commit

Permalink
feat: store writer framework IDE into project directory instead of ui…
Browse files Browse the repository at this point in the history
….json

* feat: save file into .wf directory
* feat: save components into one file per page and using json line format
  • Loading branch information
FabienArcellier committed Aug 19, 2024
1 parent aba8a6f commit 4aa4433
Show file tree
Hide file tree
Showing 9 changed files with 319 additions and 6 deletions.
11 changes: 10 additions & 1 deletion src/writer/app_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
from watchdog.observers.polling import PollingObserver

from writer import VERSION
from writer.core import EventHandlerRegistry, MiddlewareRegistry, WriterSession
from writer.core import (
EventHandlerRegistry,
MiddlewareRegistry,
WriterSession,
wf_project_write_files,
)
from writer.core_ui import ingest_bmc_component_tree
from writer.ss_types import (
AppProcessServerRequest,
Expand Down Expand Up @@ -712,6 +717,9 @@ async def update_components(self, session_id: str, payload: ComponentUpdateReque
raise PermissionError(
"Cannot update components in non-update mode.")
self.bmc_components = payload.components

wf_project_write_files(self.app_path, metadata={"writer_version": VERSION}, components=payload.components)

file_contents = {
"metadata": {
"writer_version": VERSION
Expand All @@ -720,6 +728,7 @@ async def update_components(self, session_id: str, payload: ComponentUpdateReque
}
with open(os.path.join(self.app_path, "ui.json"), "w") as f:
json.dump(file_contents, f, indent=4)

return await self.dispatch_message(session_id, ComponentUpdateRequest(
type="componentUpdate",
payload=payload
Expand Down
47 changes: 46 additions & 1 deletion src/writer/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
import base64
import contextlib
import copy
import dataclasses
import datetime
import inspect
import io
import json
import logging
import math
import multiprocessing
import os
import re
import secrets
import time
Expand Down Expand Up @@ -43,11 +43,13 @@
from writer import core_ui
from writer.core_ui import Component
from writer.ss_types import (
ComponentDefinition,
DataframeRecordAdded,
DataframeRecordRemoved,
DataframeRecordUpdated,
InstancePath,
InstancePathItem,
MetadataDefinition,
Readable,
WriterEvent,
WriterEventResult,
Expand Down Expand Up @@ -2101,6 +2103,49 @@ def build_writer_func_arguments(func: Callable, writer_args: dict) -> List[Any]:

return func_args

def wf_project_write_files(app_path: str, metadata: MetadataDefinition, components: dict[str, ComponentDefinition]) -> None:
"""
Writes the meta data of the WF project to the `.wf` directory (metadata, components, ...).
* the metadata.json file is written in json format
* a file for the root component written in jsonline format
* one file per page is created in the form `components-{id}.json` in jsonline format
>>> wf_project_write_files('app/hello', metadata={"writer_version": "0.1" }, components=...)
"""
wf_directory = os.path.join(app_path, ".wf")
if not os.path.exists(wf_directory):
os.makedirs(wf_directory)

with open(os.path.join(wf_directory, "metadata.json"), "w") as f:
json.dump(metadata, f, indent=4)

root_component = components["root"]
with io.open(os.path.join(wf_directory, "components-root.jsonl"), "w") as f:
f.write(json.dumps(root_component))

list_pages = []
for c in components.values():
if c["type"] == "page":
list_pages.append(c["id"])

for position, page_id in enumerate(list_pages):
page_components = [components[page_id]]
page_components_ids = {page_id}
for c in components.values():
if c.get("parentId", None) in page_components_ids:
page_components.append(c)
page_components_ids.add(c["id"])

with io.open(os.path.join(wf_directory, f"components-page-{position}-{page_id}.jsonl"), "w") as f:
for p in page_components:
f.write(json.dumps(p) + "\n")



def wf_project_read_files(app_path: str) -> Optional[Tuple[MetadataDefinition, dict[str, ComponentDefinition]]]:
pass


async def _async_wrapper_internal(callable_handler: Callable, arg_values: List[Any]) -> Any:
result = await callable_handler(*arg_values)
Expand Down
22 changes: 21 additions & 1 deletion src/writer/ss_types.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Any, Dict, List, Optional, Protocol, Tuple
from typing import Any, Dict, List, Optional, Protocol, Tuple, Union

from pydantic import BaseModel
from typing_extensions import Literal, TypedDict
Expand Down Expand Up @@ -177,3 +177,23 @@ class DataframeRecordRemoved(TypedDict):
class WriterEventResult(TypedDict):
ok: bool
result: Any

class MetadataDefinition(TypedDict):
"""
Declarative definition of meta for auto-completion
"""
writer_version: str

class ComponentDefinition(TypedDict):
"""
Declarative definition of a component for auto-completion
"""
id: str
type: str
content: Dict[str, Any]
isCodeManaged: Optional[bool]
position: int
parentId: Optional[str]
handlers: Optional[Dict[str, str]]
visible: Optional[Union[bool, str]]
binding: Optional[Dict]
15 changes: 15 additions & 0 deletions tests/backend/fixtures/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import os.path
from typing import Union

from . import file_fixtures

fixture_path = os.path.realpath(os.path.dirname(__file__))


def load_fixture_content(path, format: file_fixtures.FileFormat = file_fixtures.FileFormat.auto) -> Union[str, dict, list]:
"""
Load the contents of a file from the fixture folder
>>> c = load_fixture_content('obsoletes/ui_obsolete_visible.json')
"""
file_path = os.path.join(fixture_path, path)
return file_fixtures.read(file_path, format)
Loading

0 comments on commit 4aa4433

Please sign in to comment.