Skip to content

Commit

Permalink
Merge pull request #49 from sebastian-muthwill/staging
Browse files Browse the repository at this point in the history
RC v0.4.0-alpha
  • Loading branch information
sebastian-muthwill committed Nov 10, 2021
2 parents 5ee4ab2 + b1687e6 commit b429938
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 76 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ src/*
__pycache*
build/*
.vscode/*
dist/d/*
dist/*
*.code-workspace
1 change: 0 additions & 1 deletion dist/d
Submodule d deleted from b629db
Binary file removed dist/pa-docstring.exe
Binary file not shown.
8 changes: 8 additions & 0 deletions docstring_gui/main.kv
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ ScreenManager:
MDToolbar:
title: "Power Apps - Docstring"

MDLabel:
id: version_lable
text: "v0.4.0-alpha"
halign: "left"
theme_text_color: "Custom"
text_color: 1, 1, 1, 1
pos_hint: {'center_y' : .5}

MDRectangleFlatIconButton:
icon: "bug-outline"
text: "Issue"
Expand Down
8 changes: 4 additions & 4 deletions docstring_gui/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

# import powerapps classes
from powerapps_docstring.documentation import Docstring
from powerapps_docstring.powerapp import PowerApp

# import screen classes
from docstring_gui.screens.result_screen.result_screen import ResultScreen
Expand All @@ -28,11 +29,10 @@ def create_documentation(self):

# Spot check on CanvasManifest.json file. If this exists, it should be
# a correct power apps source path
if not os.path.isfile(self.source.text + "CanvasManifest.json"):
source_path = PowerApp(self.source.text).get_pa_src_path()
if not os.path.isfile(os.path.join(source_path, "CanvasManifest.json")):
self.source.error = True
self.source.helper_text = "Path is not an Power Apps source"
if not self.source.text.endswith("\\"):
self.source.text = self.source.text + "\\"
return
else:
self.source.error = False
Expand All @@ -59,7 +59,7 @@ def create_documentation(self):

# create documentation
# TODO: add try block and show error page if somethin went wrong
docstring = Docstring(self.source.text, self.output.text, config_instance)
docstring = Docstring(source_path, self.output.text, config_instance)
output_file_path = docstring.create_documentation()

# navigate to succeed page
Expand Down
62 changes: 54 additions & 8 deletions docu/PoweApps_Documentation_Guideline.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,20 @@ Based on the recomendation from Microsoft within the [learning path](https://doc
- Architecture and design (partly)
- **Technical specifications**
- End-User documentation
- Internal Marketing
- Change log

In addition to this the following things should be also documented:
In addition to this the following things should also be concidered for documentation:

- **Screen flows**
- **Connections**
- Global variables
- Context variables*
- Collections
- Project scope and definition
- Use cases and targeted user (groups)
- Overall system architecture
- Database architecture
- Deployment process
- **Connections**
- **Screen flows**
- Global variables*
- Context variables*
- Collections*
>*) can be explained within the docstring
## How to document?
Expand Down Expand Up @@ -76,11 +78,55 @@ Foo bar…

To create a docstring for the screen level, place a docstring at the beginning of the `OnVisible` propperty of the screen.

## Documentation content

### App scope and definition

This is a overall verbal description of the app project, it's intention and scope.

Write down some key information, why this app was created, which purpose does it has and
what will change if this app is implemented and used. What are the benefits? Which problem will be solved?

### Use cases and targeted user (groups)

Describe the use cases of this app and whom is this app targetting?

Usually you start with an use case diagram before creating the app. This makes clear what use cases the
app will serve and who is ment to use it. More: [Wiki - use case](https://en.wikipedia.org/wiki/Use_case)

### Overall system architecture

Describe how the system will interact with other components or systems.

Is there a flow running or is the data, which is stored somewhere, is used by another system?
Everythin what helps to get an overall picture will help.

### Database architecture

Describe your database type and architecture.

Usually an entity relationship model is created which represents the tables and their relations in your database. More: [Wiki - entity relationship model](https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model)

### Deployment process

Describe how the app is deployed, updated and maintained.

### Connections
Are created automatically.

### Screen flows
A visualization for screenflows are created in [powerapps-docstring](https://github.com/sebastian-muthwill/powerapps-docstring) automatically based on the Navigate() functions.
A visualization for screenflows is created in [powerapps-docstring](https://github.com/sebastian-muthwill/powerapps-docstring) automatically based on the Navigate() functions.

![Example screenflow](media/Screenflow_example.png) _Screenflow from example_

### Global variables

Description of your global variables

### Context variables

Description of your context variables

### Collections

Description of your collections
53 changes: 25 additions & 28 deletions example/Meeting Capture Demo-doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,11 @@ Contents

This tool helps you to keep everythin in one place during your meetings.

Key
features are:
Key features are:
- View meeting details
- capture notes and pictures of whiteboards
- assign tasks
- send meeting notes to
all attendees in one click
- send meeting notes to all attendees in one click



Expand Down Expand Up @@ -109,28 +107,28 @@ With following datasources:

:::mermaid
graph LR
WelcomeScreen ==> HomePopUpsScreen
HomeScreen ==> Sketch Screen
HomeScreen ==> CameraScreen
HomeScreen ==> EmailScreen
HomeScreen ==> AttachmentsScreen
HomeScreen ==> ExportScreen
HomeScreen ==> HomePopUpsScreen
Sketch Screen ==> HomeScreen
Sketch Screen ==> CameraScreen
CameraScreen ==> HomeScreen
CameraScreen ==> Sketch Screen
EmailScreen ==> ConfirmScreen
ConfirmScreen ==> HomeScreen
ConfirmScreen ==> FollowUpScreen
ConfirmScreen ==> WelcomeScreen
ExportScreen ==> HomeScreen
ExportScreen ==> ExportPopUpsScreen
FollowUpScreen ==> FollowUpTimesScreen
FollowUpTimesScreen ==> ConfirmScreen
HomePopUpsScreen ==> HomeScreen
ExportPopUpsScreen ==> ExportScreen
ExportPopUpsScreen ==> ConfirmScreen
WelcomeScreen(WelcomeScreen) --> HomePopUpsScreen(HomePopUpsScreen)
HomeScreen(HomeScreen) --> SketchScreen(Sketch Screen)
HomeScreen(HomeScreen) --> CameraScreen(CameraScreen)
HomeScreen(HomeScreen) --> EmailScreen(EmailScreen)
HomeScreen(HomeScreen) --> AttachmentsScreen(AttachmentsScreen)
HomeScreen(HomeScreen) --> ExportScreen(ExportScreen)
HomeScreen(HomeScreen) --> HomePopUpsScreen(HomePopUpsScreen)
SketchScreen(Sketch Screen) --> HomeScreen(HomeScreen)
SketchScreen(Sketch Screen) --> CameraScreen(CameraScreen)
CameraScreen(CameraScreen) --> HomeScreen(HomeScreen)
CameraScreen(CameraScreen) --> SketchScreen(Sketch Screen)
EmailScreen(EmailScreen) --> ConfirmScreen(ConfirmScreen)
ConfirmScreen(ConfirmScreen) --> HomeScreen(HomeScreen)
ConfirmScreen(ConfirmScreen) --> FollowUpScreen(FollowUpScreen)
ConfirmScreen(ConfirmScreen) --> WelcomeScreen(WelcomeScreen)
ExportScreen(ExportScreen) --> HomeScreen(HomeScreen)
ExportScreen(ExportScreen) --> ExportPopUpsScreen(ExportPopUpsScreen)
FollowUpScreen(FollowUpScreen) --> FollowUpTimesScreen(FollowUpTimesScreen)
FollowUpTimesScreen(FollowUpTimesScreen) --> ConfirmScreen(ConfirmScreen)
HomePopUpsScreen(HomePopUpsScreen) --> HomeScreen(HomeScreen)
ExportPopUpsScreen(ExportPopUpsScreen) --> ExportScreen(ExportScreen)
ExportPopUpsScreen(ExportPopUpsScreen) --> ConfirmScreen(ConfirmScreen)
:::
## WelcomeScreen

Expand Down Expand Up @@ -365,8 +363,7 @@ Set(ShowOverlay, true)

Create a sketch during a meeting.

The screen name "Sketch Screen" (notice the blank) akt's as a test for screen names
with blank
The screen name "Sketch Screen" (notice the blank) akt's as a test for screen names with blank

#### OnVisible

Expand Down
25 changes: 20 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os, sys, getopt
import yaml
from powerapps_docstring.powerapp import PowerApp, UnknownSourceException
from powerapps_docstring.powerapp import PowerApp, UnknownSourceException, CanvasManifestNotFoundInSourceException
from powerapps_docstring.documentation import Docstring


Expand All @@ -21,7 +21,11 @@ def main(argv):
# if programm started without arguments, we run the GUI
if len(opts) == 0:
from docstring_gui import main as gui_main
gui_main()
try:
gui_main()
except TypeError:
# when donwstream application is terminated, it will thro a TypeError exception.
pass

sys.exit(1)

Expand Down Expand Up @@ -54,6 +58,10 @@ def main(argv):
print("The source type is not valid")
print("Refere to the help with -h or --help")
sys.exit(1)
except CanvasManifestNotFoundInSourceException:
print("Exception: CanvasManifestNotFoundInSourceException: CanvasManifest.json not found in source folder!")
print("Refere to the help with -h or --help")
sys.exit(1)

# check output path
if not os.path.isdir(output_path):
Expand All @@ -75,9 +83,16 @@ def main(argv):
with open(config_file, "r", encoding='utf8') as file:
config = yaml.safe_load(file)


docstring = Docstring(pa_src_path, output_path, config)
docstring.create_documentation()
# run documentation creation process
print(f"Creating documentation for {pa_src_path}")
try:
docstring = Docstring(pa_src_path, output_path, config)
documentation_output_path = docstring.create_documentation()
print(f"Documentation created successfully: {documentation_output_path}")
sys.exit(0)
except Exception as e:
print("Error occured within documentation creation")
raise e

def print_help():
print(main.__doc__)
Expand Down
32 changes: 22 additions & 10 deletions powerapps_docstring/documentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

class Docstring():
def __init__(self, source, output, config) -> None:
self.source_path = source
self.output_path = output
self.source_path = os.path.normpath(source)
self.output_path = os.path.normpath(output)
self.parser = Parser(self.source_path)
self.config = config
self.manifest_file = self.parser.get_canvas_manifest()
Expand All @@ -18,7 +18,7 @@ def __init__(self, source, output, config) -> None:

def _get_screen_files(self):
screen_files = []
screens_path = self.source_path + "/Src/"
screens_path = os.path.join(self.source_path, "Src")

# read screen order from manifest and check if files exists
screen_order = self.manifest_file["ScreenOrder"]
Expand Down Expand Up @@ -128,7 +128,6 @@ def get_recursively(search_dict, field):
screenflow_list = [":::mermaid", "graph LR"]

screen_files = self._get_screen_files()
screens_path = self.source_path + "/Src/"

for screen in screen_files:
# check if screen has been excluded
Expand All @@ -154,7 +153,11 @@ def get_recursively(search_dict, field):
to_screen = item[start:end]
to_screen = to_screen.replace("\n", "").replace("\t", "").replace(")", "").replace("'", "")
if to_screen != None and to_screen != "" and not to_screen.startswith("[@") and to_screen not in self.config["ScreenFlow"]["ExcludeScreens"]:
screenflow_list.append(from_screen + " ==> " + to_screen)
screenflow_list.append(
"".join(from_screen.split()) + "(" + from_screen + ")" +
" --> " +
"".join(to_screen.split()) + "(" + to_screen + ")"
)

screenflow_list.append(":::")

Expand All @@ -168,13 +171,24 @@ def _create_chapter_app(self, app_name):
# # APP # #
# get contents from App.fx.yaml
app_screen = self.parser.get_screen_objects("App.fx.yaml")

# read StartScreen and OnStart propperties from App
start_screen = app_screen[1]["App As appinfo"].get("StartScreen")
on_start = app_screen[1]["App As appinfo"].get("OnStart")

# create heading for app info
self.md_file.new_line("")
self.md_file.new_line("")
self.md_file.new_header(level=1, title=app_name)

# write app info
if start_screen != None:
appinfo = self._extract_parts_from_propperty(start_screen)
self.md_file.new_line("")
self.md_file.new_header(level=2, title="StartScreen")
self.md_file.insert_code(appinfo[2],language='typescript')
self.md_file.new_line("")

if on_start != None:
appinfo = self._extract_parts_from_propperty(on_start)
if appinfo[1] != None:
Expand Down Expand Up @@ -221,7 +235,6 @@ def _create_chapter_screens(self):
self.md_file.new_line(scr_flow)

# loop thru all screens and create markdown
screens_path = self.source_path + "/Src/"
for file in self._get_screen_files():
screen_objects = self.parser.get_screen_objects(file)
self._extract_screen_content_to_markdown(screen_objects)
Expand All @@ -236,9 +249,8 @@ def create_documentation(self, format=None):
# instantiate the md file
# TODO: get title from docstring variable
app_name = self.manifest_file["PublishInfo"]["AppName"]
output_file = self.output_path + f'/{app_name}-doc'
self.md_file = MdUtils(file_name=self.output_path +
f'/{app_name}-doc', title='Power App Documentation')
output_file = os.path.join(self.output_path, f'{app_name}-doc')
self.md_file = MdUtils(file_name=output_file, title='Power App Documentation')

for chapter in self.config["DocumentStructure"]:
if chapter == "App":
Expand Down
10 changes: 5 additions & 5 deletions powerapps_docstring/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ def get_connections(self) -> dict:
"""
connections = {} # create empty dict

connections_file = self.source_path + "Connections/Connections.json"
connections_file = os.path.join(self.source_path, "Connections", "Connections.json")
if os.path.isfile(connections_file):
with open(connections_file, "r") as file:
connections = json.load(file)

return connections

def _get_screen_content(self, screen_name):
screen_path = self.source_path + "src/" + screen_name
screen_path = os.path.join(self.source_path, "src", screen_name)
screen_content = {}

with open(screen_path, "r", encoding='utf8') as file:
Expand All @@ -35,10 +35,10 @@ def get_screen_objects(self, screen_name) -> tuple:
return screen_name, screen_content

def get_canvas_manifest(self):
app_name = "PowerApp_Documentation"
# get name from CanvasManifest.json
if os.path.isfile(self.source_path + "CanvasManifest.json"):
with open(self.source_path + "CanvasManifest.json", "r", encoding="utf-8") as file:
manifest_file = os.path.join(self.source_path, "CanvasManifest.json")
if os.path.isfile(manifest_file):
with open(manifest_file, "r", encoding="utf-8") as file:
canvas_manifest = json.load(file)

return canvas_manifest
Loading

0 comments on commit b429938

Please sign in to comment.