From 0f9b555576008d33bf190d5a9c445a655d3ea64b Mon Sep 17 00:00:00 2001 From: Fabien Lelaquais <86590727+FabienLelaquais@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:21:30 +0200 Subject: [PATCH] Integrate Designer user manual from taipy-designer repository (#1126) + Access to Markdown & Builder code samples --- .gitignore | 53 ++++++------- .../gui/viselements/generic/pane.md_template | 10 +-- mkdocs.yml_template | 4 + tools/_setup_generation/setup.py | 2 + tools/_setup_generation/step_designer.py | 75 +++++++++++++++++++ tools/_setup_generation/step_gallery.py | 4 +- tools/_setup_generation/step_refman.py | 9 ++- tools/fetch_source_files.py | 15 +++- 8 files changed, 137 insertions(+), 35 deletions(-) create mode 100644 tools/_setup_generation/step_designer.py diff --git a/.gitignore b/.gitignore index 295273d5b..a80139260 100644 --- a/.gitignore +++ b/.gitignore @@ -112,29 +112,30 @@ mkdocs.yml /taipy /taipy-fe /docs/refmans/gui/viselements/index.md -docs/refmans/gui/viselements/generic/*.md -!docs/refmans/gui/viselements/generic/index.md -docs/refmans/gui/viselements/generic/charts/*.md -docs/refmans/gui/viselements/corelements/*.md -!docs/userman/gui/gui_example.ipynb -docs/userman/xrefs -docs/refmans/reference/**/*.md -!docs/refmans/reference/index.md -docs/refmans/reference_rest/*.md -!docs/refmans/reference_rest/index.md -docs/refmans/reference_guiext/ -docs/contributing/contributors.md -fe_node_modules/ -docs/tutorials/index.md -docs/tutorials/getting_started/index.md -docs/tutorials/scenario_management/index.md -docs/tutorials/visuals/index.md -docs/tutorials/integration/index.md -docs/tutorials/large_data/index.md -docs/tutorials/fundamentals/index.md -docs/gallery/index.md -docs/gallery/finance/index.md -docs/gallery/decision_support/index.md -docs/gallery/llm/index.md -docs/gallery/visualization/index.md -docs/gallery/other/index.md +/docs/refmans/gui/viselements/generic/*.md +!/docs/refmans/gui/viselements/generic/index.md +/docs/refmans/gui/viselements/generic/charts/*.md +/docs/refmans/gui/viselements/corelements/*.md +!/docs/userman/gui/gui_example.ipynb +/docs/userman/xrefs +/docs/refmans/reference/**/*.md +!/docs/refmans/reference/index.md +/docs/refmans/reference_rest/*.md +!/docs/refmans/reference_rest/index.md +/docs/refmans/reference_guiext/ +/docs/contributing/contributors.md +/fe_node_modules/ +/docs/tutorials/index.md +/docs/tutorials/getting_started/index.md +/docs/tutorials/scenario_management/index.md +/docs/tutorials/visuals/index.md +/docs/tutorials/integration/index.md +/docs/tutorials/large_data/index.md +/docs/tutorials/fundamentals/index.md +/docs/gallery/index.md +/docs/gallery/finance/index.md +/docs/gallery/decision_support/index.md +/docs/gallery/llm/index.md +/docs/gallery/visualization/index.md +/docs/gallery/other/index.md +/docs/userman/ecosystem/designer diff --git a/docs/refmans/gui/viselements/generic/pane.md_template b/docs/refmans/gui/viselements/generic/pane.md_template index 7fadb43d6..eab9f22c7 100644 --- a/docs/refmans/gui/viselements/generic/pane.md_template +++ b/docs/refmans/gui/viselements/generic/pane.md_template @@ -53,7 +53,7 @@ detailed in the examples below: # Usage -## Showing or hiding a pane {data-source="gui:doc/examples/controls/pane-simple.py"} +## Showing or hiding a pane {data-source="gui:doc/examples/blocks/pane-simple/"} Here is a simple application that shows a page with a button that a user can click to open the pane. @@ -121,7 +121,7 @@ Here is how the page shows before and after the open button is pressed: The pane closes when the user clicks on the original page area. -## Showing or hiding (simplified) {data-source="gui:doc/examples/controls/pane-simple-lambda.py"} +## Showing or hiding (simplified) {data-source="gui:doc/examples/blocks/pane-simple-lambda/"} The previous section explains how to use the `on_action` callback to open the pane when a button is pressed. Because the action is so simple (setting a variable to True), this can be simplified using @@ -165,7 +165,7 @@ Here is an alternative page definition: We set the *on_action* property of the button control to a lambda function that sets the variable *show_pane* to true, so the definition of the callback function is no longer needed. -## Choosing where the pane appears {data-source="gui:doc/examples/controls/pane-anchor.py"} +## Choosing where the pane appears {data-source="gui:doc/examples/blocks/pane-anchor/"} The [*anchor*](#p-anchor) property defines which side of the page the pane is shown on. @@ -208,7 +208,7 @@ is visible:
Pane anchored to the top
-## Showing the pane beside the page content {data-source="gui:doc/examples/controls/pane-persistent.py"} +## Showing the pane beside the page content {data-source="gui:doc/examples/blocks/pane-persistent/"} The pane is shown beside the page content instead of over it if the [*persistent*](#p-persistent) property evaluates to True. @@ -279,7 +279,7 @@ Here is how the page appears when the pane is opened or closed: -## Pane from a page definition {data-source="gui:doc/examples/controls/pane-as-page.py"} +## Pane from a page definition {data-source="gui:doc/examples/blocks/pane-as-page/"} The content of the pane can be specified as an existing page using the [*page*](#p-page) property, which can be set to a page name. This can be useful when the pane content definition is complex or diff --git a/mkdocs.yml_template b/mkdocs.yml_template index e927476f2..d69f89583 100644 --- a/mkdocs.yml_template +++ b/mkdocs.yml_template @@ -221,6 +221,10 @@ nav: - "Text edition": userman/ecosystem/studio/config/textedition.md - "GUI Markdown support": userman/ecosystem/studio/gui.md + - "Taipy Designer": + - "Taipy Designer": userman/ecosystem/designer/index.md + [DESIGNER_CONTENT] + - "Visual Elements": - "Visual Elements": refmans/gui/viselements/index.md [VISELEMENTS_CONTENT] diff --git a/tools/_setup_generation/setup.py b/tools/_setup_generation/setup.py index 075dbcda8..0e04b897d 100644 --- a/tools/_setup_generation/setup.py +++ b/tools/_setup_generation/setup.py @@ -131,6 +131,7 @@ def run_setup(root_dir: str, steps: List[SetupStep] = None): from .step_rest_refman import RestRefManStep from .step_gui_ext_refman import GuiExtRefManStep from .step_contributors import ContributorsStep + from .step_designer import DesignerStep steps = [ GalleryStep(), @@ -140,6 +141,7 @@ def run_setup(root_dir: str, steps: List[SetupStep] = None): RestRefManStep(), GuiExtRefManStep(), ContributorsStep(), + DesignerStep(), ] setup = Setup(root_dir, steps) setup.setup() diff --git a/tools/_setup_generation/step_designer.py b/tools/_setup_generation/step_designer.py new file mode 100644 index 000000000..3fd278ffa --- /dev/null +++ b/tools/_setup_generation/step_designer.py @@ -0,0 +1,75 @@ +# ########################################################################################## +# Step to generate the documentation pages for Taipy Designer, after they were copied +# locally from the taipy-designer repository. +# +# ########################################################################################## + +import os +import re +from io import StringIO + +from .setup import SetupStep, Setup + + +class DesignerStep(SetupStep): + PREFIX = "userman/ecosystem/designer" + + def __init__(self): + self.navigation = "" + + def get_id(self) -> str: + return "designer" + + def get_description(self) -> str: + return "Retrieve the Designer documentation files." + + def setup(self, setup: Setup): ... + + def enter(self, setup: Setup): + self.DESIGNER_PATH = os.path.join( + setup.docs_dir, *DesignerStep.PREFIX.split("/") + ) + self.MKDOCS_TMPL = os.path.join(self.DESIGNER_PATH, "mkdocs.yml_template") + if not os.access(self.MKDOCS_TMPL, os.R_OK): + raise FileNotFoundError( + f"FATAL - Could not read docs/{DesignerStep.PREFIX}/mkdocs.yml_template" + ) + self.navigation = self._read_mkdocs_template() + + def exit(self, setup: Setup): + setup.update_mkdocs_yaml_template( + r"^\s*\[DESIGNER_CONTENT\]\s*\n", + self.navigation if self.navigation else "", + ) + + def _read_mkdocs_template(self) -> str: + lines = [] + indentation = 0 + with open(self.MKDOCS_TMPL) as file: + collect = False + for line in file: + if line.startswith("nav:"): # Start collecting navigation + collect = True + elif re.match(r"^[\w_]+\s*?:", line): # Stop collecting navigation + if collect: + navigation = StringIO() + for navline in lines: + # Add each line with indentation removed + navigation.write(" ") + navigation.write(navline[indentation:]) + navigation.write("\n") + return navigation.getvalue() + elif collect: + if not lines: + # Retrieve initial indentation + sline = line.lstrip() + indentation = len(line) - len(sline) + sline = line.rstrip() + if sline: # Skip potential empty lines + # Add prefix to doc path + match = re.match( + r"^(\s+(?:\".*?\")|(?:[^\"]+))\s*:(:?\s*)", sline + ) + if match and sline[match.end() :]: + sline = f"{match[1]}: {DesignerStep.PREFIX}/{sline[match.end():]}" + lines.append(sline) diff --git a/tools/_setup_generation/step_gallery.py b/tools/_setup_generation/step_gallery.py index 6798551ad..58e9330da 100644 --- a/tools/_setup_generation/step_gallery.py +++ b/tools/_setup_generation/step_gallery.py @@ -10,7 +10,7 @@ # The header contains the following information: # - title: The title of the item # - category: The category of the item (fundamentals, visuals, scenario_management, -# integration, large_data, finance, decision_support, llm, visualization or other) +# integration, large_data, finance, decision_support, llm, visualization or other) # - data-keywords: A comma separated list of keywords # - short-description: A short description of the item # - img: The path to the image associated with the item @@ -69,7 +69,7 @@ def enter(self, setup: Setup): } def get_id(self) -> str: - return "gallery_step" + return "gallery" def get_description(self) -> str: return "Generates the list of items for the gallery index page from various content types." diff --git a/tools/_setup_generation/step_refman.py b/tools/_setup_generation/step_refman.py index b3a7b7189..0b3237d04 100644 --- a/tools/_setup_generation/step_refman.py +++ b/tools/_setup_generation/step_refman.py @@ -30,6 +30,8 @@ class RefManStep(SetupStep): # Entries that should be hidden for the time being HIDDEN_ENTRIES = ["get_context_id", "invoke_state_callback"] + HIDDEN_ENTRIES_FULL = ["taipy.gui.utils._css.get_style"] + # Where the Reference Manual files are generated (MUST BE relative to docs_dir) REFERENCE_REL_PATH = "refmans/reference" @@ -107,9 +109,14 @@ def read_module(module): if hasattr(e, "__module__") and e.__module__: # Handling alias Types if e.__module__.startswith(Setup.ROOT_PACKAGE): # For local build + # Remove hidden entry + if f"{e.__module__}.{entry}" in RefManStep.HIDDEN_ENTRIES_FULL: + continue if e.__class__.__name__ == "NewType": entry_type = TYPE_ID - elif e.__module__ == "typing" and hasattr(e, "__name__"): # For Readthedoc build + elif e.__module__ == "typing" and hasattr( + e, "__name__" + ): # For ReadTheDocs build # Manually remove classes from 'typing' if e.__name__ in ["NewType", "TypeVar", "overload", "cast"]: continue diff --git a/tools/fetch_source_files.py b/tools/fetch_source_files.py index a7e6d2219..547c9210c 100644 --- a/tools/fetch_source_files.py +++ b/tools/fetch_source_files.py @@ -14,7 +14,7 @@ DEST_DIR_NAME = "taipy" REPOS = ["taipy"] -PRIVATE_REPOS = ["enterprise"] +PRIVATE_REPOS = ["enterprise", "designer"] OPTIONAL_PACKAGES = {"gui": ["pyarrow", "pyngrok", "python-magic", "python-magic-bin"]} @@ -215,6 +215,19 @@ def move_files(repo: str, src_path: str): f"python {os.path.join(src_path, 'generate_notebook.py')}", shell=True, capture_output=True, text=True ) os.chdir(saved_dir) + elif repo == "taipy-designer": + designer_doc_dir = os.path.join(ROOT_DIR, "docs", "userman", "ecosystem", "designer") + safe_rmtree(designer_doc_dir) + src_documentation_dir = os.path.join(src_path, "documentation") + saved_dir = os.getcwd() + os.chdir(saved_dir) + subprocess.run( + f"python {os.path.join(src_path, 'copy_examples.py')}", shell=True, capture_output=True, text=True + ) + os.chdir(saved_dir) + shutil.copytree(os.path.join(src_documentation_dir, "taipy_docs"), designer_doc_dir) + shutil.copy(os.path.join(src_documentation_dir, "mkdocs_taipy.yml"), + os.path.join(designer_doc_dir, "mkdocs.yml_template")) else: try: