diff --git a/.gitignore b/.gitignore index 8b69396a..28d6b8a4 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ release.zip npm-debug.log* yarn-debug.log* yarn-error.log* +/public/port-0.0.0-py3-none-any.whl +/src/framework/processing/py/dist/port-0.0.0-py3-none-any.whl diff --git a/public/port-0.0.0-py3-none-any.whl b/public/port-0.0.0-py3-none-any.whl deleted file mode 100644 index 5ca44929..00000000 Binary files a/public/port-0.0.0-py3-none-any.whl and /dev/null differ diff --git a/src/framework/command_router.ts b/src/framework/command_router.ts index e3c51145..51124a01 100644 --- a/src/framework/command_router.ts +++ b/src/framework/command_router.ts @@ -1,4 +1,4 @@ -import { Command, Response, isCommandSystem, isCommandUI, CommandUI, CommandSystem } from './types/commands' +import { Command, Response, isCommandSystem, isCommandSystemExit, isCommandUI, CommandUI, CommandSystem } from './types/commands' import { CommandHandler, Bridge, VisualisationEngine } from './types/modules' export default class CommandRouter implements CommandHandler { @@ -17,14 +17,19 @@ export default class CommandRouter implements CommandHandler { } else if (isCommandUI(command)) { this.onCommandUI(command, resolve) } else { - reject(new TypeError('Unknown command' + JSON.stringify(command))) + reject(new TypeError('[CommandRouter] Unknown command' + JSON.stringify(command))) } }) } onCommandSystem (command: CommandSystem, resolve: (response: Response) => void): void { this.bridge.send(command) - resolve({ __type__: 'Response', command, payload: { __type__: 'PayloadVoid', value: undefined } }) + + if (isCommandSystemExit(command)) { + console.log("[CommandRouter] Application exit") + } else { + resolve({ __type__: 'Response', command, payload: { __type__: 'PayloadVoid', value: undefined } }) + } } onCommandUI (command: CommandUI, reject: (reason?: any) => void): void { diff --git a/src/framework/processing/py/dist/port-0.0.0-py3-none-any.whl b/src/framework/processing/py/dist/port-0.0.0-py3-none-any.whl deleted file mode 100644 index 5ca44929..00000000 Binary files a/src/framework/processing/py/dist/port-0.0.0-py3-none-any.whl and /dev/null differ diff --git a/src/framework/processing/py/port/api/props.py b/src/framework/processing/py/port/api/props.py index db8aa782..b1644bee 100644 --- a/src/framework/processing/py/port/api/props.py +++ b/src/framework/processing/py/port/api/props.py @@ -40,22 +40,6 @@ def toDict(self): return dict -@dataclass -class PropsUIFooter: - """Page footer - - Attributes: - progressPercentage: float indicating the progress in the flow - """ - progressPercentage: float - - def toDict(self): - dict = {} - dict["__type__"] = "PropsUIFooter" - dict["progressPercentage"] = self.progressPercentage - return dict - - @dataclass class PropsUIPromptConfirm: """Retry submitting a file page @@ -195,12 +179,10 @@ class PropsUIPageDonation: platform: the platform name the user is curently in the process of donating data from header: page header body: main body of the page, see the individual classes for an explanation - footer: page footer """ platform: str header: PropsUIHeader body: PropsUIPromptRadioInput | PropsUIPromptConsentForm | PropsUIPromptFileInput | PropsUIPromptConfirm - footer: PropsUIFooter def toDict(self): dict = {} @@ -208,7 +190,6 @@ def toDict(self): dict["platform"] = self.platform dict["header"] = self.header.toDict() dict["body"] = self.body.toDict() - dict["footer"] = self.footer.toDict() return dict diff --git a/src/framework/processing/py/port/main.py b/src/framework/processing/py/port/main.py index 7b0bb78b..3bcc269e 100644 --- a/src/framework/processing/py/port/main.py +++ b/src/framework/processing/py/port/main.py @@ -1,5 +1,6 @@ from collections.abc import Generator from port.script import process +from port.api.commands import CommandSystemExit class ScriptWrapper(Generator): @@ -7,8 +8,12 @@ def __init__(self, script): self.script = script def send(self, data): - command = self.script.send(data) - return command.toDict() + try: + command = self.script.send(data) + except StopIteration: + return CommandSystemExit(0, "End of script").toDict() + else: + return command.toDict() def throw(self, type=None, value=None, traceback=None): raise StopIteration diff --git a/src/framework/processing/py/port/script.py b/src/framework/processing/py/port/script.py index 806ff3b1..aeefa1d8 100644 --- a/src/framework/processing/py/port/script.py +++ b/src/framework/processing/py/port/script.py @@ -6,82 +6,56 @@ def process(sessionId): - yield donate(f"{sessionId}-tracking", '[{ "message": "user entered script" }]') - - platforms = ["Twitter", "Facebook", "Instagram", "Youtube"] - - subflows = len(platforms) - steps = 2 - step_percentage = (100/subflows)/steps - - # progress in % - progress = 0 - - for index, platform in enumerate(platforms): - meta_data = [] - meta_data.append(("debug", f"{platform}: start")) - - # STEP 1: select the file - progress += step_percentage - data = None - while True: - meta_data.append(("debug", f"{platform}: prompt file")) - promptFile = prompt_file(platform, "application/zip, text/plain") - fileResult = yield render_donation_page(platform, promptFile, progress) - if fileResult.__type__ == 'PayloadString': - meta_data.append(("debug", f"{platform}: extracting file")) - extractionResult = doSomethingWithTheFile(platform, fileResult.value) - if extractionResult != 'invalid': - meta_data.append(("debug", f"{platform}: extraction successful, go to consent form")) - data = extractionResult - break - else: - meta_data.append(("debug", f"{platform}: prompt confirmation to retry file selection")) - retry_result = yield render_donation_page(platform, retry_confirmation(platform), progress) - if retry_result.__type__ == 'PayloadTrue': - meta_data.append(("debug", f"{platform}: skip due to invalid file")) - continue - else: - meta_data.append(("debug", f"{platform}: retry prompt file")) - break - else: - meta_data.append(("debug", f"{platform}: skip to next step")) + key = "zip-contents-example" + meta_data = [] + meta_data.append(("debug", f"{key}: start")) + + # STEP 1: select the file + data = None + while True: + meta_data.append(("debug", f"{key}: prompt file")) + promptFile = prompt_file("application/zip, text/plain") + fileResult = yield render_donation_page(promptFile) + if fileResult.__type__ == 'PayloadString': + meta_data.append(("debug", f"{key}: extracting file")) + extractionResult = doSomethingWithTheFile(fileResult.value) + if extractionResult != 'invalid': + meta_data.append(("debug", f"{key}: extraction successful, go to consent form")) + data = extractionResult break + else: + meta_data.append(("debug", f"{key}: prompt confirmation to retry file selection")) + retry_result = yield render_donation_page(retry_confirmation()) + if retry_result.__type__ == 'PayloadTrue': + meta_data.append(("debug", f"{key}: skip due to invalid file")) + continue + else: + meta_data.append(("debug", f"{key}: retry prompt file")) + break - # STEP 2: ask for consent - progress += step_percentage - if data is not None: - meta_data.append(("debug", f"{platform}: prompt consent")) - prompt = prompt_consent(platform, data, meta_data) - consent_result = yield render_donation_page(platform, prompt, progress) - if consent_result.__type__ == "PayloadJSON": - meta_data.append(("debug", f"{platform}: donate consent data")) - yield donate(f"{sessionId}-{platform}", consent_result.value) - - yield exit(0, "Success") - yield render_end_page() - - -def render_end_page(): - page = props.PropsUIPageEnd() - return CommandUIRender(page) + # STEP 2: ask for consent + meta_data.append(("debug", f"{key}: prompt consent")) + prompt = prompt_consent(data, meta_data) + consent_result = yield render_donation_page(prompt) + if consent_result.__type__ == "PayloadJSON": + meta_data.append(("debug", f"{key}: donate consent data")) + yield donate(f"{sessionId}-{key}", consent_result.value) -def render_donation_page(platform, body, progress): +def render_donation_page(body): header = props.PropsUIHeader(props.Translatable({ - "en": platform, - "nl": platform + "en": "Port flow example", + "nl": "Port voorbeeld flow" })) - footer = props.PropsUIFooter(progress) - page = props.PropsUIPageDonation(platform, header, body, footer) + page = props.PropsUIPageDonation("Zip", header, body) return CommandUIRender(page) -def retry_confirmation(platform): +def retry_confirmation(): text = props.Translatable({ - "en": f"Unfortunately, we cannot process your {platform} file. Continue, if you are sure that you selected the right file. Try again to select a different file.", - "nl": f"Helaas, kunnen we uw {platform} bestand niet verwerken. Weet u zeker dat u het juiste bestand heeft gekozen? Ga dan verder. Probeer opnieuw als u een ander bestand wilt kiezen." + "en": "Unfortunately, we cannot process your file. Continue, if you are sure that you selected the right file. Try again to select a different file.", + "nl": "Helaas, kunnen we uw bestand niet verwerken. Weet u zeker dat u het juiste bestand heeft gekozen? Ga dan verder. Probeer opnieuw als u een ander bestand wilt kiezen." }) ok = props.Translatable({ "en": "Try again", @@ -94,16 +68,16 @@ def retry_confirmation(platform): return props.PropsUIPromptConfirm(text, ok, cancel) -def prompt_file(platform, extensions): +def prompt_file(extensions): description = props.Translatable({ - "en": f"Please follow the download instructions and choose the file that you stored on your device. Click “Skip” at the right bottom, if you do not have a {platform} file. ", - "nl": f"Volg de download instructies en kies het bestand dat u opgeslagen heeft op uw apparaat. Als u geen {platform} bestand heeft klik dan op “Overslaan” rechts onder." + "en": "Please select any zip file stored on your device.", + "nl": "Selecteer een willekeurige zip file die u heeft opgeslagen op uw apparaat." }) return props.PropsUIPromptFileInput(description, extensions) -def doSomethingWithTheFile(platform, filename): +def doSomethingWithTheFile(filename): return extract_zip_contents(filename) @@ -121,7 +95,7 @@ def extract_zip_contents(filename): return "invalid" -def prompt_consent(id, data, meta_data): +def prompt_consent(data, meta_data): table_title = props.Translatable({ "en": "Zip file contents", @@ -133,15 +107,19 @@ def prompt_consent(id, data, meta_data): "nl": "Log berichten" }) - data_frame = pd.DataFrame(data, columns=["filename", "compressed size", "size"]) - table = props.PropsUIPromptConsentFormTable("zip_content", table_title, data_frame) + tables=[] + if data is not None: + data_frame = pd.DataFrame(data, columns=["filename", "compressed size", "size"]) + tables = [props.PropsUIPromptConsentFormTable("zip_content", table_title, data_frame)] + meta_frame = pd.DataFrame(meta_data, columns=["type", "message"]) meta_table = props.PropsUIPromptConsentFormTable("log_messages", log_title, meta_frame) - return props.PropsUIPromptConsentForm([table], [meta_table]) + return props.PropsUIPromptConsentForm(tables, [meta_table]) def donate(key, json_string): return CommandSystemDonate(key, json_string) + def exit(code, info): - return CommandSystemExit(code, info) \ No newline at end of file + return CommandSystemExit(code, info) diff --git a/src/framework/types/elements.ts b/src/framework/types/elements.ts index 26847aeb..0e6f33dc 100644 --- a/src/framework/types/elements.ts +++ b/src/framework/types/elements.ts @@ -330,16 +330,6 @@ export function isPropsUIHeader (arg: any): arg is PropsUIHeader { return isInstanceOf(arg, 'PropsUIHeader', ['title']) } -// Footer - -export interface PropsUIFooter { - __type__: 'PropsUIFooter' - progressPercentage: number -} -export function isPropsUIFooter (arg: any): arg is PropsUIFooter { - return isInstanceOf(arg, 'PropsUIFooter', ['progressPercentage']) -} - // TABLE export interface PropsUITable { diff --git a/src/framework/types/pages.ts b/src/framework/types/pages.ts index f89a8553..c91136c7 100644 --- a/src/framework/types/pages.ts +++ b/src/framework/types/pages.ts @@ -1,5 +1,5 @@ import { isInstanceOf } from '../helpers' -import { PropsUIFooter, PropsUIHeader } from './elements' +import { PropsUIHeader } from './elements' import { PropsUIPromptFileInput, PropsUIPromptConfirm, PropsUIPromptConsentForm, PropsUIPromptRadioInput } from './prompts' export type PropsUIPage = @@ -23,10 +23,9 @@ export interface PropsUIPageDonation { platform: string header: PropsUIHeader body: PropsUIPromptFileInput | PropsUIPromptConfirm | PropsUIPromptConsentForm | PropsUIPromptRadioInput - footer: PropsUIFooter } export function isPropsUIPageDonation (arg: any): arg is PropsUIPageDonation { - return isInstanceOf(arg, 'PropsUIPageDonation', ['platform', 'header', 'body', 'footer']) + return isInstanceOf(arg, 'PropsUIPageDonation', ['platform', 'header', 'body']) } export interface PropsUIPageEnd {