diff --git a/alfred/apps.py b/alfred/apps.py
new file mode 100644
index 000000000..359dcf4aa
--- /dev/null
+++ b/alfred/apps.py
@@ -0,0 +1,45 @@
+import os
+
+from writer import audit_and_fix, wf_project
+
+import alfred
+
+
+@alfred.command('apps.update', help='update the apps in the repo to the latest version')
+@alfred.option('--app', help='the path of the app to update')
+def apps_update(app: str = None):
+ import writer
+
+ if app is not None:
+ apps = [app]
+ else:
+ apps = [
+ 'apps/ai-starter',
+ 'apps/default',
+ 'apps/hello',
+ 'apps/pdg-tutorial',
+ 'apps/quickstart',
+ 'apps/text-demo',
+ 'tests/backend/testapp',
+ 'tests/backend/testbasicauth',
+ 'tests/backend/testmultiapp/app1',
+ 'tests/backend/testmultiapp/app2',
+ ]
+
+ for app in apps:
+ abs_path = os.path.realpath(app)
+ if not os.path.isdir(abs_path):
+ continue
+
+ if os.path.isfile(os.path.join(abs_path, "ui.json")):
+ print(f'{app} : migrate ui.json')
+ wf_project.migrate_obsolete_ui_json(abs_path)
+
+ metadata, components = wf_project.read_files(abs_path)
+ if metadata.get('writer_version') == writer.VERSION:
+ print("The app is already up to date")
+ else:
+ metadata['writer_version'] = writer.VERSION
+ components = audit_and_fix.fix_components(components)
+ wf_project.write_files(abs_path, metadata, components)
+ print(f"{app} : app is up to date")
diff --git a/alfred/npm.py b/alfred/npm.py
index 7a4f52584..e6946dfcb 100644
--- a/alfred/npm.py
+++ b/alfred/npm.py
@@ -5,7 +5,8 @@
@alfred.command("npm.lint", help="lint check npm packages")
def npm_lint():
- alfred.run("npm run ui:lint:ci")
+ alfred.run("npm run ui:lint.ci")
+ alfred.run("npm run ui:custom.check")
@alfred.command("npm.e2e", help="run e2e tests")
@alfred.option('--browser', '-b', help="run e2e tests on specified browser", default='chromium')
diff --git a/apps/ai-starter/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl b/apps/ai-starter/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl
new file mode 100644
index 000000000..a270e24ec
--- /dev/null
+++ b/apps/ai-starter/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl
@@ -0,0 +1,3 @@
+{"id": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "type": "page", "content": {"pageMode": "compact"}, "isCodeManaged": false, "position": 0, "parentId": "root", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf", "type": "header", "content": {"text": "@{my_app.title}"}, "isCodeManaged": false, "position": 0, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "ejpasds0o8qyjs1n", "type": "section", "content": {"title": "Section Title"}, "isCodeManaged": false, "position": 1, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
diff --git a/apps/ai-starter/.wf/components-root.jsonl b/apps/ai-starter/.wf/components-root.jsonl
new file mode 100644
index 000000000..93d45e4bf
--- /dev/null
+++ b/apps/ai-starter/.wf/components-root.jsonl
@@ -0,0 +1 @@
+{"id": "root", "type": "root", "content": {"appName": "AI Starter"}, "isCodeManaged": false, "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
\ No newline at end of file
diff --git a/apps/ai-starter/.wf/metadata.json b/apps/ai-starter/.wf/metadata.json
new file mode 100644
index 000000000..1f76abe5a
--- /dev/null
+++ b/apps/ai-starter/.wf/metadata.json
@@ -0,0 +1,3 @@
+{
+ "writer_version": "0.7.0rc2"
+}
\ No newline at end of file
diff --git a/apps/ai-starter/ui.json b/apps/ai-starter/ui.json
deleted file mode 100644
index f127cddc9..000000000
--- a/apps/ai-starter/ui.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "metadata": {
- "writer_version": "0.6.0rc3"
- },
- "components": {
- "root": {
- "id": "root",
- "type": "root",
- "content": {
- "appName": "AI Starter"
- },
- "isCodeManaged": false,
- "position": 0,
- "handlers": {},
- "visible": true
- },
- "c0f99a9e-5004-4e75-a6c6-36f17490b134": {
- "id": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "type": "page",
- "content": {
- "pageMode": "compact"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "root",
- "handlers": {},
- "visible": true
- },
- "bebc5fe9-63a7-46a7-b0fa-62303555cfaf": {
- "id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf",
- "type": "header",
- "content": {
- "text": "@{my_app.title}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "handlers": {},
- "visible": true
- },
- "ejpasds0o8qyjs1n": {
- "id": "ejpasds0o8qyjs1n",
- "type": "section",
- "content": {
- "title": "Section Title"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "handlers": {},
- "visible": true
- }
- }
-}
\ No newline at end of file
diff --git a/apps/default/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl b/apps/default/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl
new file mode 100644
index 000000000..2ac428329
--- /dev/null
+++ b/apps/default/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl
@@ -0,0 +1,11 @@
+{"id": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "type": "page", "content": {"pageMode": "compact"}, "isCodeManaged": false, "position": 0, "parentId": "root", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf", "type": "header", "content": {"text": "@{my_app.title}"}, "isCodeManaged": false, "position": 0, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "28d3885b-0fb8-4d41-97c6-978540015431", "type": "section", "content": {"title": "", "containerShadow": "0px 4px 11px -12px #000000"}, "isCodeManaged": false, "position": 1, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "9556c0e3-8584-4ac9-903f-908a775a33ec", "type": "button", "content": {"text": " Increment", "icon": "arrow_upward"}, "isCodeManaged": false, "position": 1, "parentId": "0d05bc9f-1655-4d0b-bc9b-c2f4c71a5117", "handlers": {"click": "increment"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "51d1554e-1b88-461c-9353-1419cba0053a", "type": "button", "content": {"text": "Decrement", "icon": "arrow_downward"}, "isCodeManaged": false, "position": 0, "parentId": "0d05bc9f-1655-4d0b-bc9b-c2f4c71a5117", "handlers": {"click": "decrement"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "0d05bc9f-1655-4d0b-bc9b-c2f4c71a5117", "type": "horizontalstack", "content": {"contentHAlign": "center"}, "isCodeManaged": false, "position": 0, "parentId": "f3777e75-3659-4d44-8ef7-aeec0d06855b", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "172a14df-f73a-44fa-8fb1-e8648e7d32d2", "type": "metric", "content": {"metricValue": "@{counter}", "note": "@{message}", "name": "Counter"}, "isCodeManaged": false, "position": 0, "parentId": "c2519671-9ce7-44e7-ba4e-b0efda9cb20e", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "d4a5e62c-c6fe-49c4-80d4-33862af8727d", "type": "columns", "content": {}, "isCodeManaged": false, "position": 0, "parentId": "28d3885b-0fb8-4d41-97c6-978540015431", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "f3777e75-3659-4d44-8ef7-aeec0d06855b", "type": "column", "content": {"title": "", "width": "1", "contentHAlign": "center", "contentVAlign": "center"}, "isCodeManaged": false, "position": 2, "parentId": "d4a5e62c-c6fe-49c4-80d4-33862af8727d", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "c2519671-9ce7-44e7-ba4e-b0efda9cb20e", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 0, "parentId": "d4a5e62c-c6fe-49c4-80d4-33862af8727d", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "d4a71819-7444-4083-a1c7-7995452a7abf", "type": "separator", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "d4a5e62c-c6fe-49c4-80d4-33862af8727d", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
diff --git a/apps/default/.wf/components-root.jsonl b/apps/default/.wf/components-root.jsonl
new file mode 100644
index 000000000..b08c078fe
--- /dev/null
+++ b/apps/default/.wf/components-root.jsonl
@@ -0,0 +1 @@
+{"id": "root", "type": "root", "content": {"appName": "My App"}, "isCodeManaged": false, "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
\ No newline at end of file
diff --git a/apps/default/.wf/metadata.json b/apps/default/.wf/metadata.json
new file mode 100644
index 000000000..1f76abe5a
--- /dev/null
+++ b/apps/default/.wf/metadata.json
@@ -0,0 +1,3 @@
+{
+ "writer_version": "0.7.0rc2"
+}
\ No newline at end of file
diff --git a/apps/default/ui.json b/apps/default/ui.json
deleted file mode 100644
index 471d19b6d..000000000
--- a/apps/default/ui.json
+++ /dev/null
@@ -1,146 +0,0 @@
-{
- "metadata": {
- "writer_version": "0.6.2rc3"
- },
- "components": {
- "root": {
- "id": "root",
- "type": "root",
- "content": {
- "appName": "My App"
- },
- "isCodeManaged": false,
- "position": 0,
- "handlers": {}
- },
- "c0f99a9e-5004-4e75-a6c6-36f17490b134": {
- "id": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "type": "page",
- "content": {
- "pageMode": "compact"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "root",
- "handlers": {}
- },
- "bebc5fe9-63a7-46a7-b0fa-62303555cfaf": {
- "id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf",
- "type": "header",
- "content": {
- "text": "@{my_app.title}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "handlers": {}
- },
- "28d3885b-0fb8-4d41-97c6-978540015431": {
- "id": "28d3885b-0fb8-4d41-97c6-978540015431",
- "type": "section",
- "content": {
- "title": "",
- "containerShadow": "0px 4px 11px -12px #000000"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "handlers": {}
- },
- "9556c0e3-8584-4ac9-903f-908a775a33ec": {
- "id": "9556c0e3-8584-4ac9-903f-908a775a33ec",
- "type": "button",
- "content": {
- "text": " Increment",
- "icon": "arrow_upward"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "0d05bc9f-1655-4d0b-bc9b-c2f4c71a5117",
- "handlers": {
- "click": "increment"
- }
- },
- "51d1554e-1b88-461c-9353-1419cba0053a": {
- "id": "51d1554e-1b88-461c-9353-1419cba0053a",
- "type": "button",
- "content": {
- "text": "Decrement",
- "icon": "arrow_downward"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "0d05bc9f-1655-4d0b-bc9b-c2f4c71a5117",
- "handlers": {
- "click": "decrement"
- }
- },
- "0d05bc9f-1655-4d0b-bc9b-c2f4c71a5117": {
- "id": "0d05bc9f-1655-4d0b-bc9b-c2f4c71a5117",
- "type": "horizontalstack",
- "content": {
- "contentHAlign": "center"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "f3777e75-3659-4d44-8ef7-aeec0d06855b",
- "handlers": {}
- },
- "172a14df-f73a-44fa-8fb1-e8648e7d32d2": {
- "id": "172a14df-f73a-44fa-8fb1-e8648e7d32d2",
- "type": "metric",
- "content": {
- "metricValue": "@{counter}",
- "note": "@{message}",
- "name": "Counter"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "c2519671-9ce7-44e7-ba4e-b0efda9cb20e",
- "handlers": {}
- },
- "d4a5e62c-c6fe-49c4-80d4-33862af8727d": {
- "id": "d4a5e62c-c6fe-49c4-80d4-33862af8727d",
- "type": "columns",
- "content": {},
- "isCodeManaged": false,
- "position": 0,
- "parentId": "28d3885b-0fb8-4d41-97c6-978540015431",
- "handlers": {}
- },
- "f3777e75-3659-4d44-8ef7-aeec0d06855b": {
- "id": "f3777e75-3659-4d44-8ef7-aeec0d06855b",
- "type": "column",
- "content": {
- "title": "",
- "width": "1",
- "contentHAlign": "center",
- "contentVAlign": "center"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "d4a5e62c-c6fe-49c4-80d4-33862af8727d",
- "handlers": {}
- },
- "c2519671-9ce7-44e7-ba4e-b0efda9cb20e": {
- "id": "c2519671-9ce7-44e7-ba4e-b0efda9cb20e",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "d4a5e62c-c6fe-49c4-80d4-33862af8727d",
- "handlers": {}
- },
- "d4a71819-7444-4083-a1c7-7995452a7abf": {
- "id": "d4a71819-7444-4083-a1c7-7995452a7abf",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "d4a5e62c-c6fe-49c4-80d4-33862af8727d",
- "handlers": {}
- }
- }
-}
\ No newline at end of file
diff --git a/apps/hello/.wf/components-page-0-bb4d0e86-619e-4367-a180-be28ab6059f4.jsonl b/apps/hello/.wf/components-page-0-bb4d0e86-619e-4367-a180-be28ab6059f4.jsonl
new file mode 100644
index 000000000..f3f7c9f71
--- /dev/null
+++ b/apps/hello/.wf/components-page-0-bb4d0e86-619e-4367-a180-be28ab6059f4.jsonl
@@ -0,0 +1,76 @@
+{"id": "bb4d0e86-619e-4367-a180-be28ab6059f4", "type": "page", "content": {"pageMode": "", "key": "main"}, "isCodeManaged": false, "position": 0, "parentId": "root"}
+{"id": "84378aea-b64c-49a3-9539-f854532279ee", "type": "header", "content": {"text": "HACKER PIGEONS", "emptinessColor": "#000000", "accentColor": "#ffffff"}, "isCodeManaged": false, "position": 0, "parentId": "bb4d0e86-619e-4367-a180-be28ab6059f4"}
+{"id": "92a2c0c8-7ab4-4865-b7eb-ed437408c8f5", "type": "columns", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "bb4d0e86-619e-4367-a180-be28ab6059f4"}
+{"id": "d1e01ce1-fab1-4a6e-91a1-1f45f9e57aa5", "type": "column", "content": {"width": "1", "isCollapsible": "", "title": "", "isSticky": "yes"}, "isCodeManaged": false, "position": 0, "parentId": "92a2c0c8-7ab4-4865-b7eb-ed437408c8f5"}
+{"id": "0569937e-c72c-4fb9-820e-2ae56e17bcc0", "type": "column", "content": {"width": "1.61"}, "isCodeManaged": false, "position": 1, "parentId": "92a2c0c8-7ab4-4865-b7eb-ed437408c8f5"}
+{"id": "9c30af6d-4ee5-4782-9169-0f361d67fa76", "type": "section", "content": {"title": ""}, "isCodeManaged": false, "position": 0, "parentId": "d1e01ce1-fab1-4a6e-91a1-1f45f9e57aa5"}
+{"id": "7fdd1d02-53de-4466-bd3c-4822cbc2694f", "type": "image", "content": {"src": "static/pigeon1.jpg?8", "caption": ""}, "isCodeManaged": false, "position": 0, "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76"}
+{"id": "ee919cd6-8153-4f34-8c6a-bfc1153df360", "type": "tabs", "content": {}, "isCodeManaged": false, "position": 0, "parentId": "0569937e-c72c-4fb9-820e-2ae56e17bcc0"}
+{"id": "c6392876-7cfd-4680-8725-b04f43ff294f", "type": "tab", "content": {"name": "Data and Charts"}, "isCodeManaged": false, "position": 0, "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360"}
+{"id": "da00a61f-0ee2-434e-acd6-228d32eae5c6", "type": "tab", "content": {"name": "Repeater"}, "isCodeManaged": false, "position": 2, "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360"}
+{"id": "d0298b1c-7c64-4b58-a018-db97dd49675b", "type": "separator", "content": {}, "isCodeManaged": false, "position": 3, "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f"}
+{"id": "f1d6bc8e-a780-4ae5-8b7c-082fe8a6867d", "type": "dataframe", "content": {"dataframe": "@{main_df}", "showIndex": "", "enableSearch": "yes", "enableDownload": "yes"}, "isCodeManaged": false, "position": 4, "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f"}
+{"id": "fbad9feb-5c88-4425-bb17-0d138286a875", "type": "sidebar", "content": {"startCollapsed": "yes"}, "isCodeManaged": false, "position": -2, "parentId": "bb4d0e86-619e-4367-a180-be28ab6059f4"}
+{"id": "7e625201-20c2-4b05-951c-d825de28b216", "type": "section", "content": {"title": "Filter data"}, "isCodeManaged": false, "position": 0, "parentId": "fbad9feb-5c88-4425-bb17-0d138286a875"}
+{"id": "385247e5-5c89-4352-a598-b8da81146a5a", "type": "sliderinput", "content": {"label": "Minimum weight", "minValue": "300", "maxValue": "600", "stepSize": "1"}, "isCodeManaged": false, "position": 1, "parentId": "7e625201-20c2-4b05-951c-d825de28b216", "handlers": {"wf-number-change": "update"}, "binding": {"eventType": "wf-number-change", "stateRef": "filter.min_weight"}}
+{"id": "10c156df-7464-4889-8b69-1b54cb1ee80a", "type": "sliderinput", "content": {"label": "Minimum length", "minValue": "25", "maxValue": "35", "stepSize": "1"}, "isCodeManaged": false, "position": 0, "parentId": "7e625201-20c2-4b05-951c-d825de28b216", "handlers": {"wf-number-change": "update"}, "binding": {"eventType": "wf-number-change", "stateRef": "filter.min_length"}}
+{"id": "70d82458-a08f-4005-8f96-dc8d3ba92fad", "type": "section", "content": {"title": "About this app"}, "isCodeManaged": false, "position": 1, "parentId": "fbad9feb-5c88-4425-bb17-0d138286a875"}
+{"id": "12e11005-3b5e-4bd8-9a8c-fc7b8cb757d0", "type": "text", "content": {"text": "This app is meant to serve as a lighthearted introduction to the framework. It's not a comprehensive demonstration of its capabilities."}, "isCodeManaged": false, "position": 0, "parentId": "70d82458-a08f-4005-8f96-dc8d3ba92fad"}
+{"id": "7b710d37-1c68-4d06-a65a-e6596ccc826a", "type": "text", "content": {"text": "In a city plagued by technology gone awry, a group of unlikely heroes emerges. Introducing the Hacker Pigeons, a team of intelligent and resourceful pigeons on a mission to save their home from destruction. Follow their journey as they battle against malicious hackers, and prove that even the smallest creatures can make a big difference.", "alignment": ""}, "isCodeManaged": false, "position": 4, "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76"}
+{"id": "b9cb10e5-1ead-448b-afcc-909e23afb72a", "type": "columns", "content": {}, "isCodeManaged": false, "position": 2, "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f"}
+{"id": "31c1b0d5-bfb6-4304-82bd-1687d492f0a2", "type": "heading", "content": {"text": "Pigeon Power: Birds Tackle Data Apps", "alignment": ""}, "isCodeManaged": false, "position": 1, "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76"}
+{"id": "3cc9c5e9-6c77-401d-ab82-7805d9df760c", "type": "tab", "content": {"name": "Layout"}, "isCodeManaged": false, "position": 1, "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360"}
+{"id": "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff", "type": "columns", "content": {}, "isCodeManaged": false, "position": 0, "parentId": "3cc9c5e9-6c77-401d-ab82-7805d9df760c"}
+{"id": "25dda22d-1b18-4584-aa99-aaae9f3b8edf", "type": "column", "content": {"width": "1", "isCollapsible": "yes", "title": "Markdown", "contentVAlign": ""}, "isCodeManaged": false, "position": 0, "parentId": "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff"}
+{"id": "b1ee642e-f2e7-453b-a6ef-3d96eea37140", "type": "column", "content": {"title": "HTML Element", "width": "1", "isCollapsible": "", "startCollapsed": "", "contentHAlign": "center"}, "isCodeManaged": false, "position": 2, "parentId": "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff"}
+{"id": "d1f43b6f-5b0f-4c8f-95bf-a92dd7ed723b", "type": "text", "content": {"text": "\n### Role Distribution\n\nThe Hacker Pigeons _dataframe_ consists of five distinct roles:\n\n1. Leader\n2. Developer\n3. Data Expert\n4. Designer\n5. Security Expert\n\nThe **role distribution** among the hacker pigeons can be analysed to understand the composition of the secret society and the proportions of various roles.", "useMarkdown": "yes"}, "isCodeManaged": false, "position": 2, "parentId": "25dda22d-1b18-4584-aa99-aaae9f3b8edf"}
+{"id": "71766c0c-e1e5-4675-9dd0-3aa2627773a0", "type": "html", "content": {"styles": "{\n \"padding\": \"16px\",\n \"margin\": \"24px\",\n \"min-height\": \"64px\",\n \"min-width\": \"64px\",\n \"max-width\": \"90%\",\n \"border-radius\": \"8px\",\n \"transform\": \"rotate(-3deg)\",\n \"box-shadow\": \"0 4px 16px -8px black\"\n}"}, "isCodeManaged": false, "position": 0, "parentId": "b1ee642e-f2e7-453b-a6ef-3d96eea37140"}
+{"id": "c73602a6-453d-4ccf-b8e3-b1774ab4ff17", "type": "text", "content": {"text": "Use the HTML Element component when you need additional control."}, "isCodeManaged": false, "position": 1, "parentId": "71766c0c-e1e5-4675-9dd0-3aa2627773a0"}
+{"id": "573f095f-94a7-43e4-a94e-b2f69439a164", "type": "separator", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff"}
+{"id": "feedc43f-a7cf-499b-962e-8170f1032b69", "type": "text", "content": {"text": "You can use Markdown, as shown below."}, "isCodeManaged": false, "position": 0, "parentId": "25dda22d-1b18-4584-aa99-aaae9f3b8edf"}
+{"id": "1ee57415-557d-4529-be99-36f4d91fdf69", "type": "separator", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "25dda22d-1b18-4584-aa99-aaae9f3b8edf"}
+{"id": "a36b75bc-58e6-48ba-bdef-0824e6b21e8d", "type": "html", "content": {"styles": "{\n \"padding\": \"16px\",\n \"margin\": \"24px\",\n \"min-height\": \"64px\",\n \"min-width\": \"64px\",\n \"max-width\": \"90%\",\n \"border-radius\": \"8px\",\n \"transform\": \"rotate(3deg)\",\n \"box-shadow\": \"0 4px 16px -8px black\"\n}"}, "isCodeManaged": false, "position": 1, "parentId": "b1ee642e-f2e7-453b-a6ef-3d96eea37140"}
+{"id": "5da5e007-d60a-4313-9d21-885deae7b37d", "type": "text", "content": {"text": "You can put other Writer Framework components inside HTML Elements."}, "isCodeManaged": false, "position": 1, "parentId": "a36b75bc-58e6-48ba-bdef-0824e6b21e8d"}
+{"id": "85120b55-69c6-4b50-853a-bbbf73ff8121", "type": "tab", "content": {"name": "Timer"}, "isCodeManaged": false, "position": 4, "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360"}
+{"id": "db4c66d6-1eb7-44d3-a2d4-65d0b3e5cf12", "type": "dataframe", "content": {"dataframe": "@{random_df}", "fontStyle": "monospace", "enableSearch": "", "enableDownload": ""}, "isCodeManaged": false, "position": 1, "parentId": "85120b55-69c6-4b50-853a-bbbf73ff8121"}
+{"id": "09ddb2da-6fa3-4157-8da3-4d5d44a6a58d", "type": "horizontalstack", "content": {"contentHAlign": "start"}, "isCodeManaged": false, "position": 0, "parentId": "85120b55-69c6-4b50-853a-bbbf73ff8121"}
+{"id": "50a05488-d6fe-47bf-b681-36870d04f5d7", "type": "timer", "content": {"intervalMs": "1000", "isActive": ""}, "isCodeManaged": false, "position": 0, "parentId": "09ddb2da-6fa3-4157-8da3-4d5d44a6a58d", "handlers": {"wf-tick": "handle_timer_tick"}}
+{"id": "e296866a-75d2-4677-b55d-3c1456113b89", "type": "text", "content": {"text": "Refreshing automatically using a timer."}, "isCodeManaged": false, "position": 1, "parentId": "09ddb2da-6fa3-4157-8da3-4d5d44a6a58d"}
+{"id": "fdf38e46-c01e-4a93-94d5-e187f9e4c823", "type": "text", "content": {"text": "_pgcf_ stands for \"Pigeon Coefficient\" and is a meaningless, randomly-generated value.", "useMarkdown": "yes", "primaryTextColor": "#8a8a8a"}, "isCodeManaged": false, "position": 2, "parentId": "85120b55-69c6-4b50-853a-bbbf73ff8121"}
+{"id": "c921816d-6d45-4ce3-9c18-2c78ff850e0e", "type": "html", "content": {"element": "img", "styles": "{\n \"filter\": \"hue-rotate(calc(80deg + @{hue_rotation}deg))\"\n}", "attrs": "{ \"src\": \"static/pigeon1.jpg?3\"}"}, "isCodeManaged": false, "position": 0, "parentId": "71766c0c-e1e5-4675-9dd0-3aa2627773a0"}
+{"id": "c684f61e-0c79-4cb1-af9f-46c9cab5dfea", "type": "html", "content": {"element": "img", "styles": "{\n \"filter\": \"hue-rotate(calc(140deg + @{hue_rotation}deg))\"\n}", "attrs": "{ \"src\": \"static/pigeon1.jpg?3\"}"}, "isCodeManaged": false, "position": 0, "parentId": "a36b75bc-58e6-48ba-bdef-0824e6b21e8d"}
+{"id": "ee82e035-cfb2-4d00-95ce-ccbb9eb2dbb9", "type": "sliderinput", "content": {"label": "Hue rotation", "minValue": "0", "maxValue": "360", "stepSize": "1"}, "isCodeManaged": false, "position": 2, "parentId": "b1ee642e-f2e7-453b-a6ef-3d96eea37140", "binding": {"eventType": "wf-number-change", "stateRef": "hue_rotation"}}
+{"id": "c9bb4720-d07a-4fd8-bc53-5bda8dc64046", "type": "text", "content": {"text": "As shown above, you can use _HTML Element_ components together with state references.", "useMarkdown": "yes"}, "isCodeManaged": false, "position": 3, "parentId": "b1ee642e-f2e7-453b-a6ef-3d96eea37140"}
+{"id": "6a490318-239e-4fe9-a56b-f0f33d628c87", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 1, "parentId": "b9cb10e5-1ead-448b-afcc-909e23afb72a"}
+{"id": "de70a15a-2ff6-42d2-ab12-c7fc9c3ed4e1", "type": "heading", "content": {"text": "Highlighted Members", "headingType": "h2", "alignment": "center"}, "isCodeManaged": false, "position": 0, "parentId": "da00a61f-0ee2-434e-acd6-228d32eae5c6"}
+{"id": "2f4969e2-e248-43ed-9e63-222fc35250e2", "type": "columns", "content": {}, "isCodeManaged": false, "position": 2, "parentId": "da00a61f-0ee2-434e-acd6-228d32eae5c6"}
+{"id": "f46cd60d-f01e-4390-a161-4353006b72a1", "type": "repeater", "content": {"repeaterObject": "@{highlighted_members}", "keyVariable": "itemId", "valueVariable": "item"}, "isCodeManaged": false, "position": 0, "parentId": "2f4969e2-e248-43ed-9e63-222fc35250e2"}
+{"id": "0dd29423-3867-478a-997e-eeaafb6b811e", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 0, "parentId": "f46cd60d-f01e-4390-a161-4353006b72a1"}
+{"id": "2d326b15-da90-496e-86e8-7fdd4bcbe822", "type": "section", "content": {"title": "@{item.name} \u2b50\ufe0f", "containerBackgroundColor": "#F5F5F9"}, "isCodeManaged": false, "position": 0, "parentId": "0dd29423-3867-478a-997e-eeaafb6b811e"}
+{"id": "7ea0d29a-5dca-4b6c-a067-322ccaee5032", "type": "text", "content": {"text": "You can use a _Repeater_ component to repeat components, based on a dictionary.", "useMarkdown": "yes"}, "isCodeManaged": false, "position": 4, "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"}
+{"id": "cd611ce2-f594-4b55-9932-d48e657b2e31", "type": "text", "content": {"text": "**Role:** @{item.role}\n", "useMarkdown": "yes"}, "isCodeManaged": false, "position": 1, "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"}
+{"id": "9d6ee245-b8f7-4391-9934-89598b7fa9f8", "type": "separator", "content": {}, "isCodeManaged": false, "position": 0, "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"}
+{"id": "01c33c6e-3788-4b5d-b7aa-2addaa7b503f", "type": "text", "content": {"text": "The following Hacker Pigeons have made an impressive contribution this month.\nLet's come together to recognise and celebrate this success.", "alignment": "center"}, "isCodeManaged": false, "position": 1, "parentId": "da00a61f-0ee2-434e-acd6-228d32eae5c6"}
+{"id": "e0e2391e-7bab-4c68-ad92-841942cb12fb", "type": "text", "content": {"text": "The ability @{item.name} demonstrated in @{item.specialty} has earned them this recognition.", "useMarkdown": "yes"}, "isCodeManaged": false, "position": 2, "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"}
+{"id": "4ef4655b-45ca-495c-9f8d-fa1d7ae3565e", "type": "separator", "content": {}, "isCodeManaged": false, "position": 3, "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"}
+{"id": "f67c98aa-3a7b-4f40-ac1f-0dd4aa06e22d", "type": "plotlygraph", "content": {"spec": "@{scatter_chart}"}, "isCodeManaged": false, "position": 0, "parentId": "6a490318-239e-4fe9-a56b-f0f33d628c87", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "6d895924-e808-44aa-a119-f4e2d7f394f3", "type": "column", "content": {"width": "1", "contentHAlign": "", "contentVAlign": ""}, "isCodeManaged": false, "position": 0, "parentId": "b9cb10e5-1ead-448b-afcc-909e23afb72a"}
+{"id": "70bd9ea8-baa9-4e1d-bce5-deee6a3c5440", "type": "plotlygraph", "content": {"spec": "@{role_chart}"}, "isCodeManaged": false, "position": 0, "parentId": "6d895924-e808-44aa-a119-f4e2d7f394f3", "handlers": {}}
+{"id": "8c8dd54f-af2c-4d6d-9603-dfea11cf326b", "type": "metric", "content": {"metricValue": "@{metrics.average_weight}gr", "name": "Average weight", "note": "@{metrics.average_weight_note}", "description": ""}, "isCodeManaged": false, "position": 0, "parentId": "feb9ca67-6670-483d-a895-22b031426a13", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f", "type": "columns", "content": {}, "isCodeManaged": false, "position": 0, "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "feb9ca67-6670-483d-a895-22b031426a13", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 0, "parentId": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "3b325899-e560-40ea-ba54-9c55967af1e3", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 1, "parentId": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "a0cd99db-0cbe-40ca-b9cb-b1670ec60dd8", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 2, "parentId": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "5dcd137b-76bd-4a5f-ae5c-5b629035500e", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 3, "parentId": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "6a81f847-4d1d-4110-9cc1-12c716150e66", "type": "metric", "content": {"metricValue": "@{metrics.average_length}cm", "name": "Average length", "note": "@{metrics.average_length_note}", "description": ""}, "isCodeManaged": false, "position": 0, "parentId": "3b325899-e560-40ea-ba54-9c55967af1e3", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "8e54e9d2-a7c8-4f74-897f-fa5791cd82da", "type": "metric", "content": {"metricValue": "@{metrics.average_bmi}", "name": "Average BMI", "note": "@{metrics.average_bmi_note}", "description": ""}, "isCodeManaged": false, "position": 0, "parentId": "a0cd99db-0cbe-40ca-b9cb-b1670ec60dd8", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "07f50628-4679-48a8-9a5d-07dcaf171afb", "type": "metric", "content": {"metricValue": "@{metrics.diversity}", "name": "Diversity Index", "description": "", "note": "@{metrics.diversity_note}"}, "isCodeManaged": false, "position": 0, "parentId": "5dcd137b-76bd-4a5f-ae5c-5b629035500e", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "4cca0893-5ad7-4152-b805-5c87babc4dee", "type": "separator", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "03f422ce-bc36-4000-8eb1-da1cc00948c9", "type": "button", "content": {"text": "Read the story", "icon": "library_books"}, "isCodeManaged": false, "position": 5, "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76", "handlers": {"click": "$goToPage_story"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "e1ax8ctt8lrao0e4", "type": "tab", "content": {"name": "Pagination"}, "isCodeManaged": false, "position": 3, "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "j3jkho6tb97u0onr", "type": "repeater", "content": {"keyVariable": "itemId", "valueVariable": "item", "repeaterObject": "@{paginated_members}"}, "isCodeManaged": false, "position": 0, "parentId": "e1ax8ctt8lrao0e4", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "4wzaubf275w17gac", "type": "section", "content": {"title": "@{item.name} \u2b50\ufe0f", "containerBackgroundColor": "#F5F5F9"}, "isCodeManaged": false, "position": 0, "parentId": "j3jkho6tb97u0onr", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "19binb4yi70gesho", "type": "text", "content": {"text": "**Role:** @{item.role}\n", "useMarkdown": "yes"}, "isCodeManaged": false, "position": 0, "parentId": "4wzaubf275w17gac"}
+{"id": "zfp1koasiuleygmz", "type": "pagination", "content": {"page": "@{paginated_members_page}", "pageSize": "@{paginated_members_page_size}", "totalItems": "@{paginated_members_total_items}", "pageSizeOptions": "1,2,5", "pageSizeShowAll": "no", "jumpTo": "no", "urlParam": "no"}, "isCodeManaged": false, "position": 1, "parentId": "e1ax8ctt8lrao0e4", "handlers": {"wf-change-page": "handle_paginated_members_page_change", "wf-change-page-size": "handle_paginated_members_page_size_change"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "b27lw9ex8ig3x17p", "type": "tags", "content": {"tags": "{\n \"fiction\": \"fiction\",\n \"inspirational\": \"inspirational\",\n \"ai-generated\": \"ai-generated\"\n}", "seed": ""}, "isCodeManaged": false, "position": 2, "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76", "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "804e15bf-11a7-463d-8082-f46ea3acac1b", "type": "separator", "content": {}, "isCodeManaged": false, "position": 3, "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76"}
diff --git a/apps/hello/.wf/components-page-1-23bc1387-26ed-4ff2-8565-b027c2960c3c.jsonl b/apps/hello/.wf/components-page-1-23bc1387-26ed-4ff2-8565-b027c2960c3c.jsonl
new file mode 100644
index 000000000..d1421fbb9
--- /dev/null
+++ b/apps/hello/.wf/components-page-1-23bc1387-26ed-4ff2-8565-b027c2960c3c.jsonl
@@ -0,0 +1,15 @@
+{"id": "23bc1387-26ed-4ff2-8565-b027c2960c3c", "type": "page", "content": {"key": "story", "buttonColor": "#242424", "buttonTextColor": "#ffffff", "containerBackgroundColor": "#4F4F4F", "emptinessColor": "#333333", "primaryTextColor": "#ffffff", "separatorColor": "rgba(0, 0, 0, 0.2)"}, "isCodeManaged": false, "position": 1, "parentId": "root", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "1d195388-35a3-43e1-b825-1d263b100a28", "type": "header", "content": {"text": "HACKER PIGEONS"}, "isCodeManaged": false, "position": 0, "parentId": "23bc1387-26ed-4ff2-8565-b027c2960c3c", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "771dc336-69b2-400e-9ea3-e881e2332c9d", "type": "section", "content": {"title": "The story"}, "isCodeManaged": false, "position": 0, "parentId": "dfaae7f9-db20-4f70-a376-919bdc7b6010", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "9c77aee4-e2a0-4e8b-9c2b-377f939bb51e", "type": "text", "content": {"text": "@{story.text}"}, "isCodeManaged": false, "position": 1, "parentId": "771dc336-69b2-400e-9ea3-e881e2332c9d"}
+{"id": "90fbfa9d-3178-4fc2-b445-c31e1acfa6a7", "type": "button", "content": {"text": "Go back to the main page", "icon": "arrow_back"}, "isCodeManaged": false, "position": 0, "parentId": "9bb8a686-7013-4af7-a89e-d89c7754120d", "handlers": {"click": "$goToPage_main"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "8fe33adf-a5ea-4c7a-8d1d-59cc4dc14f05", "type": "columns", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "23bc1387-26ed-4ff2-8565-b027c2960c3c", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "7402263c-cb8b-412d-b170-e6dc6ffcb706", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 1, "parentId": "8fe33adf-a5ea-4c7a-8d1d-59cc4dc14f05", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "dfaae7f9-db20-4f70-a376-919bdc7b6010", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 0, "parentId": "8fe33adf-a5ea-4c7a-8d1d-59cc4dc14f05", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "5bc38721-8b48-43d5-a454-ee5ebe713a4c", "type": "section", "content": {"title": ""}, "isCodeManaged": false, "position": 0, "parentId": "7402263c-cb8b-412d-b170-e6dc6ffcb706"}
+{"id": "42ab5c3d-21fc-4e88-befd-33e52fd15e8b", "type": "image", "content": {"src": "static/pigeon1.jpg", "caption": ""}, "isCodeManaged": false, "position": 0, "parentId": "5bc38721-8b48-43d5-a454-ee5ebe713a4c"}
+{"id": "9bb8a686-7013-4af7-a89e-d89c7754120d", "type": "horizontalstack", "content": {"contentHAlign": "start"}, "isCodeManaged": false, "position": 2, "parentId": "771dc336-69b2-400e-9ea3-e881e2332c9d", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "2df56a4b-b6e7-423d-a7a1-5d23c77f65fa", "type": "heading", "content": {"text": "Each page can have its own style", "alignment": ""}, "isCodeManaged": false, "position": 1, "parentId": "5bc38721-8b48-43d5-a454-ee5ebe713a4c"}
+{"id": "1272b52c-d97c-4c20-ba6b-19abe1ec0abc", "type": "separator", "content": {}, "isCodeManaged": false, "position": 0, "parentId": "771dc336-69b2-400e-9ea3-e881e2332c9d", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "77cb256b-ef12-4a55-a051-500497f41302", "type": "text", "content": {"text": "It's easy to switch between pages and it can be done from the frontend (via Writer Framework Builder) and from the backend (via Python)."}, "isCodeManaged": false, "position": 2, "parentId": "5bc38721-8b48-43d5-a454-ee5ebe713a4c", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "ed010441-0cac-4aa5-9e6f-97228e0c3536", "type": "button", "content": {"text": "Download this story", "icon": "download"}, "isCodeManaged": false, "position": 1, "parentId": "9bb8a686-7013-4af7-a89e-d89c7754120d", "handlers": {"click": "handle_story_download"}, "visible": {"expression": true, "binding": "", "reversed": false}}
diff --git a/apps/hello/.wf/components-root.jsonl b/apps/hello/.wf/components-root.jsonl
new file mode 100644
index 000000000..746b76e3a
--- /dev/null
+++ b/apps/hello/.wf/components-root.jsonl
@@ -0,0 +1 @@
+{"id": "root", "type": "root", "content": {"appName": "Hello", "emptinessColor": "#ffffff"}, "isCodeManaged": false, "position": 0}
\ No newline at end of file
diff --git a/apps/hello/.wf/metadata.json b/apps/hello/.wf/metadata.json
new file mode 100644
index 000000000..1f76abe5a
--- /dev/null
+++ b/apps/hello/.wf/metadata.json
@@ -0,0 +1,3 @@
+{
+ "writer_version": "0.7.0rc2"
+}
\ No newline at end of file
diff --git a/apps/hello/ui.json b/apps/hello/ui.json
deleted file mode 100644
index 6db57e02f..000000000
--- a/apps/hello/ui.json
+++ /dev/null
@@ -1,1185 +0,0 @@
-{
- "metadata": {
- "writer_version": "0.6.2rc3"
- },
- "components": {
- "root": {
- "id": "root",
- "type": "root",
- "content": {
- "appName": "Hello",
- "emptinessColor": "#ffffff"
- },
- "isCodeManaged": false,
- "position": 0
- },
- "bb4d0e86-619e-4367-a180-be28ab6059f4": {
- "id": "bb4d0e86-619e-4367-a180-be28ab6059f4",
- "type": "page",
- "content": {
- "pageMode": "",
- "key": "main"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "root"
- },
- "84378aea-b64c-49a3-9539-f854532279ee": {
- "id": "84378aea-b64c-49a3-9539-f854532279ee",
- "type": "header",
- "content": {
- "text": "HACKER PIGEONS",
- "emptinessColor": "#000000",
- "accentColor": "#ffffff"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "bb4d0e86-619e-4367-a180-be28ab6059f4"
- },
- "92a2c0c8-7ab4-4865-b7eb-ed437408c8f5": {
- "id": "92a2c0c8-7ab4-4865-b7eb-ed437408c8f5",
- "type": "columns",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "bb4d0e86-619e-4367-a180-be28ab6059f4"
- },
- "d1e01ce1-fab1-4a6e-91a1-1f45f9e57aa5": {
- "id": "d1e01ce1-fab1-4a6e-91a1-1f45f9e57aa5",
- "type": "column",
- "content": {
- "width": "1",
- "isCollapsible": "",
- "title": "",
- "isSticky": "yes"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "92a2c0c8-7ab4-4865-b7eb-ed437408c8f5"
- },
- "0569937e-c72c-4fb9-820e-2ae56e17bcc0": {
- "id": "0569937e-c72c-4fb9-820e-2ae56e17bcc0",
- "type": "column",
- "content": {
- "width": "1.61"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "92a2c0c8-7ab4-4865-b7eb-ed437408c8f5"
- },
- "9c30af6d-4ee5-4782-9169-0f361d67fa76": {
- "id": "9c30af6d-4ee5-4782-9169-0f361d67fa76",
- "type": "section",
- "content": {
- "title": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "d1e01ce1-fab1-4a6e-91a1-1f45f9e57aa5"
- },
- "7fdd1d02-53de-4466-bd3c-4822cbc2694f": {
- "id": "7fdd1d02-53de-4466-bd3c-4822cbc2694f",
- "type": "image",
- "content": {
- "src": "static/pigeon1.jpg?8",
- "caption": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76",
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "ee919cd6-8153-4f34-8c6a-bfc1153df360": {
- "id": "ee919cd6-8153-4f34-8c6a-bfc1153df360",
- "type": "tabs",
- "content": {},
- "isCodeManaged": false,
- "position": 0,
- "parentId": "0569937e-c72c-4fb9-820e-2ae56e17bcc0"
- },
- "c6392876-7cfd-4680-8725-b04f43ff294f": {
- "id": "c6392876-7cfd-4680-8725-b04f43ff294f",
- "type": "tab",
- "content": {
- "name": "Data and Charts"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360"
- },
- "da00a61f-0ee2-434e-acd6-228d32eae5c6": {
- "id": "da00a61f-0ee2-434e-acd6-228d32eae5c6",
- "type": "tab",
- "content": {
- "name": "Repeater"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360"
- },
- "d0298b1c-7c64-4b58-a018-db97dd49675b": {
- "id": "d0298b1c-7c64-4b58-a018-db97dd49675b",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 3,
- "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f"
- },
- "f1d6bc8e-a780-4ae5-8b7c-082fe8a6867d": {
- "id": "f1d6bc8e-a780-4ae5-8b7c-082fe8a6867d",
- "type": "dataframe",
- "content": {
- "dataframe": "@{main_df}",
- "showIndex": "",
- "enableSearch": "yes",
- "enableDownload": "yes"
- },
- "isCodeManaged": false,
- "position": 4,
- "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f"
- },
- "fbad9feb-5c88-4425-bb17-0d138286a875": {
- "id": "fbad9feb-5c88-4425-bb17-0d138286a875",
- "type": "sidebar",
- "content": {
- "startCollapsed": "yes"
- },
- "isCodeManaged": false,
- "position": -2,
- "parentId": "bb4d0e86-619e-4367-a180-be28ab6059f4"
- },
- "7e625201-20c2-4b05-951c-d825de28b216": {
- "id": "7e625201-20c2-4b05-951c-d825de28b216",
- "type": "section",
- "content": {
- "title": "Filter data"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "fbad9feb-5c88-4425-bb17-0d138286a875"
- },
- "385247e5-5c89-4352-a598-b8da81146a5a": {
- "id": "385247e5-5c89-4352-a598-b8da81146a5a",
- "type": "sliderinput",
- "content": {
- "label": "Minimum weight",
- "minValue": "300",
- "maxValue": "600",
- "stepSize": "1"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "7e625201-20c2-4b05-951c-d825de28b216",
- "handlers": {
- "wf-number-change": "update"
- },
- "binding": {
- "eventType": "wf-number-change",
- "stateRef": "filter.min_weight"
- }
- },
- "10c156df-7464-4889-8b69-1b54cb1ee80a": {
- "id": "10c156df-7464-4889-8b69-1b54cb1ee80a",
- "type": "sliderinput",
- "content": {
- "label": "Minimum length",
- "minValue": "25",
- "maxValue": "35",
- "stepSize": "1"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "7e625201-20c2-4b05-951c-d825de28b216",
- "handlers": {
- "wf-number-change": "update"
- },
- "binding": {
- "eventType": "wf-number-change",
- "stateRef": "filter.min_length"
- }
- },
- "70d82458-a08f-4005-8f96-dc8d3ba92fad": {
- "id": "70d82458-a08f-4005-8f96-dc8d3ba92fad",
- "type": "section",
- "content": {
- "title": "About this app"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "fbad9feb-5c88-4425-bb17-0d138286a875"
- },
- "12e11005-3b5e-4bd8-9a8c-fc7b8cb757d0": {
- "id": "12e11005-3b5e-4bd8-9a8c-fc7b8cb757d0",
- "type": "text",
- "content": {
- "text": "This app is meant to serve as a lighthearted introduction to the framework. It's not a comprehensive demonstration of its capabilities."
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "70d82458-a08f-4005-8f96-dc8d3ba92fad"
- },
- "7b710d37-1c68-4d06-a65a-e6596ccc826a": {
- "id": "7b710d37-1c68-4d06-a65a-e6596ccc826a",
- "type": "text",
- "content": {
- "text": "In a city plagued by technology gone awry, a group of unlikely heroes emerges. Introducing the Hacker Pigeons, a team of intelligent and resourceful pigeons on a mission to save their home from destruction. Follow their journey as they battle against malicious hackers, and prove that even the smallest creatures can make a big difference.",
- "alignment": ""
- },
- "isCodeManaged": false,
- "position": 4,
- "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76"
- },
- "b9cb10e5-1ead-448b-afcc-909e23afb72a": {
- "id": "b9cb10e5-1ead-448b-afcc-909e23afb72a",
- "type": "columns",
- "content": {},
- "isCodeManaged": false,
- "position": 2,
- "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f"
- },
- "31c1b0d5-bfb6-4304-82bd-1687d492f0a2": {
- "id": "31c1b0d5-bfb6-4304-82bd-1687d492f0a2",
- "type": "heading",
- "content": {
- "text": "Pigeon Power: Birds Tackle Data Apps",
- "alignment": ""
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76"
- },
- "3cc9c5e9-6c77-401d-ab82-7805d9df760c": {
- "id": "3cc9c5e9-6c77-401d-ab82-7805d9df760c",
- "type": "tab",
- "content": {
- "name": "Layout"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360"
- },
- "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff": {
- "id": "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff",
- "type": "columns",
- "content": {},
- "isCodeManaged": false,
- "position": 0,
- "parentId": "3cc9c5e9-6c77-401d-ab82-7805d9df760c"
- },
- "25dda22d-1b18-4584-aa99-aaae9f3b8edf": {
- "id": "25dda22d-1b18-4584-aa99-aaae9f3b8edf",
- "type": "column",
- "content": {
- "width": "1",
- "isCollapsible": "yes",
- "title": "Markdown",
- "contentVAlign": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff"
- },
- "b1ee642e-f2e7-453b-a6ef-3d96eea37140": {
- "id": "b1ee642e-f2e7-453b-a6ef-3d96eea37140",
- "type": "column",
- "content": {
- "title": "HTML Element",
- "width": "1",
- "isCollapsible": "",
- "startCollapsed": "",
- "contentHAlign": "center"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff"
- },
- "d1f43b6f-5b0f-4c8f-95bf-a92dd7ed723b": {
- "id": "d1f43b6f-5b0f-4c8f-95bf-a92dd7ed723b",
- "type": "text",
- "content": {
- "text": "\n### Role Distribution\n\nThe Hacker Pigeons _dataframe_ consists of five distinct roles:\n\n1. Leader\n2. Developer\n3. Data Expert\n4. Designer\n5. Security Expert\n\nThe **role distribution** among the hacker pigeons can be analysed to understand the composition of the secret society and the proportions of various roles.",
- "useMarkdown": "yes"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "25dda22d-1b18-4584-aa99-aaae9f3b8edf"
- },
- "71766c0c-e1e5-4675-9dd0-3aa2627773a0": {
- "id": "71766c0c-e1e5-4675-9dd0-3aa2627773a0",
- "type": "html",
- "content": {
- "styles": "{\n \"padding\": \"16px\",\n \"margin\": \"24px\",\n \"min-height\": \"64px\",\n \"min-width\": \"64px\",\n \"max-width\": \"90%\",\n \"border-radius\": \"8px\",\n \"transform\": \"rotate(-3deg)\",\n \"box-shadow\": \"0 4px 16px -8px black\"\n}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "b1ee642e-f2e7-453b-a6ef-3d96eea37140"
- },
- "c73602a6-453d-4ccf-b8e3-b1774ab4ff17": {
- "id": "c73602a6-453d-4ccf-b8e3-b1774ab4ff17",
- "type": "text",
- "content": {
- "text": "Use the HTML Element component when you need additional control."
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "71766c0c-e1e5-4675-9dd0-3aa2627773a0"
- },
- "573f095f-94a7-43e4-a94e-b2f69439a164": {
- "id": "573f095f-94a7-43e4-a94e-b2f69439a164",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "fb22acfc-cdb5-44b6-9e97-76c3a51a8fff"
- },
- "feedc43f-a7cf-499b-962e-8170f1032b69": {
- "id": "feedc43f-a7cf-499b-962e-8170f1032b69",
- "type": "text",
- "content": {
- "text": "You can use Markdown, as shown below."
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "25dda22d-1b18-4584-aa99-aaae9f3b8edf"
- },
- "1ee57415-557d-4529-be99-36f4d91fdf69": {
- "id": "1ee57415-557d-4529-be99-36f4d91fdf69",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "25dda22d-1b18-4584-aa99-aaae9f3b8edf"
- },
- "a36b75bc-58e6-48ba-bdef-0824e6b21e8d": {
- "id": "a36b75bc-58e6-48ba-bdef-0824e6b21e8d",
- "type": "html",
- "content": {
- "styles": "{\n \"padding\": \"16px\",\n \"margin\": \"24px\",\n \"min-height\": \"64px\",\n \"min-width\": \"64px\",\n \"max-width\": \"90%\",\n \"border-radius\": \"8px\",\n \"transform\": \"rotate(3deg)\",\n \"box-shadow\": \"0 4px 16px -8px black\"\n}"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "b1ee642e-f2e7-453b-a6ef-3d96eea37140"
- },
- "5da5e007-d60a-4313-9d21-885deae7b37d": {
- "id": "5da5e007-d60a-4313-9d21-885deae7b37d",
- "type": "text",
- "content": {
- "text": "You can put other Writer Framework components inside HTML Elements."
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "a36b75bc-58e6-48ba-bdef-0824e6b21e8d"
- },
- "85120b55-69c6-4b50-853a-bbbf73ff8121": {
- "id": "85120b55-69c6-4b50-853a-bbbf73ff8121",
- "type": "tab",
- "content": {
- "name": "Timer"
- },
- "isCodeManaged": false,
- "position": 4,
- "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360"
- },
- "db4c66d6-1eb7-44d3-a2d4-65d0b3e5cf12": {
- "id": "db4c66d6-1eb7-44d3-a2d4-65d0b3e5cf12",
- "type": "dataframe",
- "content": {
- "dataframe": "@{random_df}",
- "fontStyle": "monospace",
- "enableSearch": "",
- "enableDownload": ""
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "85120b55-69c6-4b50-853a-bbbf73ff8121"
- },
- "09ddb2da-6fa3-4157-8da3-4d5d44a6a58d": {
- "id": "09ddb2da-6fa3-4157-8da3-4d5d44a6a58d",
- "type": "horizontalstack",
- "content": {
- "contentHAlign": "start"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "85120b55-69c6-4b50-853a-bbbf73ff8121"
- },
- "50a05488-d6fe-47bf-b681-36870d04f5d7": {
- "id": "50a05488-d6fe-47bf-b681-36870d04f5d7",
- "type": "timer",
- "content": {
- "intervalMs": "1000",
- "isActive": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "09ddb2da-6fa3-4157-8da3-4d5d44a6a58d",
- "handlers": {
- "wf-tick": "handle_timer_tick"
- }
- },
- "e296866a-75d2-4677-b55d-3c1456113b89": {
- "id": "e296866a-75d2-4677-b55d-3c1456113b89",
- "type": "text",
- "content": {
- "text": "Refreshing automatically using a timer."
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "09ddb2da-6fa3-4157-8da3-4d5d44a6a58d"
- },
- "fdf38e46-c01e-4a93-94d5-e187f9e4c823": {
- "id": "fdf38e46-c01e-4a93-94d5-e187f9e4c823",
- "type": "text",
- "content": {
- "text": "_pgcf_ stands for \"Pigeon Coefficient\" and is a meaningless, randomly-generated value.",
- "useMarkdown": "yes",
- "primaryTextColor": "#8a8a8a"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "85120b55-69c6-4b50-853a-bbbf73ff8121"
- },
- "c921816d-6d45-4ce3-9c18-2c78ff850e0e": {
- "id": "c921816d-6d45-4ce3-9c18-2c78ff850e0e",
- "type": "html",
- "content": {
- "element": "img",
- "styles": "{\n \"filter\": \"hue-rotate(calc(80deg + @{hue_rotation}deg))\"\n}",
- "attrs": "{ \"src\": \"static/pigeon1.jpg?3\"}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "71766c0c-e1e5-4675-9dd0-3aa2627773a0"
- },
- "c684f61e-0c79-4cb1-af9f-46c9cab5dfea": {
- "id": "c684f61e-0c79-4cb1-af9f-46c9cab5dfea",
- "type": "html",
- "content": {
- "element": "img",
- "styles": "{\n \"filter\": \"hue-rotate(calc(140deg + @{hue_rotation}deg))\"\n}",
- "attrs": "{ \"src\": \"static/pigeon1.jpg?3\"}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "a36b75bc-58e6-48ba-bdef-0824e6b21e8d"
- },
- "ee82e035-cfb2-4d00-95ce-ccbb9eb2dbb9": {
- "id": "ee82e035-cfb2-4d00-95ce-ccbb9eb2dbb9",
- "type": "sliderinput",
- "content": {
- "label": "Hue rotation",
- "minValue": "0",
- "maxValue": "360",
- "stepSize": "1"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "b1ee642e-f2e7-453b-a6ef-3d96eea37140",
- "binding": {
- "eventType": "wf-number-change",
- "stateRef": "hue_rotation"
- }
- },
- "c9bb4720-d07a-4fd8-bc53-5bda8dc64046": {
- "id": "c9bb4720-d07a-4fd8-bc53-5bda8dc64046",
- "type": "text",
- "content": {
- "text": "As shown above, you can use _HTML Element_ components together with state references.",
- "useMarkdown": "yes"
- },
- "isCodeManaged": false,
- "position": 3,
- "parentId": "b1ee642e-f2e7-453b-a6ef-3d96eea37140"
- },
- "6a490318-239e-4fe9-a56b-f0f33d628c87": {
- "id": "6a490318-239e-4fe9-a56b-f0f33d628c87",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "b9cb10e5-1ead-448b-afcc-909e23afb72a"
- },
- "de70a15a-2ff6-42d2-ab12-c7fc9c3ed4e1": {
- "id": "de70a15a-2ff6-42d2-ab12-c7fc9c3ed4e1",
- "type": "heading",
- "content": {
- "text": "Highlighted Members",
- "headingType": "h2",
- "alignment": "center"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "da00a61f-0ee2-434e-acd6-228d32eae5c6"
- },
- "2f4969e2-e248-43ed-9e63-222fc35250e2": {
- "id": "2f4969e2-e248-43ed-9e63-222fc35250e2",
- "type": "columns",
- "content": {},
- "isCodeManaged": false,
- "position": 2,
- "parentId": "da00a61f-0ee2-434e-acd6-228d32eae5c6"
- },
- "f46cd60d-f01e-4390-a161-4353006b72a1": {
- "id": "f46cd60d-f01e-4390-a161-4353006b72a1",
- "type": "repeater",
- "content": {
- "repeaterObject": "@{highlighted_members}",
- "keyVariable": "itemId",
- "valueVariable": "item"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "2f4969e2-e248-43ed-9e63-222fc35250e2"
- },
- "0dd29423-3867-478a-997e-eeaafb6b811e": {
- "id": "0dd29423-3867-478a-997e-eeaafb6b811e",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "f46cd60d-f01e-4390-a161-4353006b72a1"
- },
- "2d326b15-da90-496e-86e8-7fdd4bcbe822": {
- "id": "2d326b15-da90-496e-86e8-7fdd4bcbe822",
- "type": "section",
- "content": {
- "title": "@{item.name} \u2b50\ufe0f",
- "containerBackgroundColor": "#F5F5F9"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "0dd29423-3867-478a-997e-eeaafb6b811e"
- },
- "7ea0d29a-5dca-4b6c-a067-322ccaee5032": {
- "id": "7ea0d29a-5dca-4b6c-a067-322ccaee5032",
- "type": "text",
- "content": {
- "text": "You can use a _Repeater_ component to repeat components, based on a dictionary.",
- "useMarkdown": "yes"
- },
- "isCodeManaged": false,
- "position": 4,
- "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"
- },
- "cd611ce2-f594-4b55-9932-d48e657b2e31": {
- "id": "cd611ce2-f594-4b55-9932-d48e657b2e31",
- "type": "text",
- "content": {
- "text": "**Role:** @{item.role}\n",
- "useMarkdown": "yes"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"
- },
- "9d6ee245-b8f7-4391-9934-89598b7fa9f8": {
- "id": "9d6ee245-b8f7-4391-9934-89598b7fa9f8",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 0,
- "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"
- },
- "01c33c6e-3788-4b5d-b7aa-2addaa7b503f": {
- "id": "01c33c6e-3788-4b5d-b7aa-2addaa7b503f",
- "type": "text",
- "content": {
- "text": "The following Hacker Pigeons have made an impressive contribution this month.\nLet's come together to recognise and celebrate this success.",
- "alignment": "center"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "da00a61f-0ee2-434e-acd6-228d32eae5c6"
- },
- "e0e2391e-7bab-4c68-ad92-841942cb12fb": {
- "id": "e0e2391e-7bab-4c68-ad92-841942cb12fb",
- "type": "text",
- "content": {
- "text": "The ability @{item.name} demonstrated in @{item.specialty} has earned them this recognition.",
- "useMarkdown": "yes"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"
- },
- "4ef4655b-45ca-495c-9f8d-fa1d7ae3565e": {
- "id": "4ef4655b-45ca-495c-9f8d-fa1d7ae3565e",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 3,
- "parentId": "2d326b15-da90-496e-86e8-7fdd4bcbe822"
- },
- "f67c98aa-3a7b-4f40-ac1f-0dd4aa06e22d": {
- "id": "f67c98aa-3a7b-4f40-ac1f-0dd4aa06e22d",
- "type": "plotlygraph",
- "content": {
- "spec": "@{scatter_chart}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "6a490318-239e-4fe9-a56b-f0f33d628c87",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "6d895924-e808-44aa-a119-f4e2d7f394f3": {
- "id": "6d895924-e808-44aa-a119-f4e2d7f394f3",
- "type": "column",
- "content": {
- "width": "1",
- "contentHAlign": "",
- "contentVAlign": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "b9cb10e5-1ead-448b-afcc-909e23afb72a"
- },
- "70bd9ea8-baa9-4e1d-bce5-deee6a3c5440": {
- "id": "70bd9ea8-baa9-4e1d-bce5-deee6a3c5440",
- "type": "plotlygraph",
- "content": {
- "spec": "@{role_chart}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "6d895924-e808-44aa-a119-f4e2d7f394f3",
- "handlers": {}
- },
- "8c8dd54f-af2c-4d6d-9603-dfea11cf326b": {
- "id": "8c8dd54f-af2c-4d6d-9603-dfea11cf326b",
- "type": "metric",
- "content": {
- "metricValue": "@{metrics.average_weight}gr",
- "name": "Average weight",
- "note": "@{metrics.average_weight_note}",
- "description": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "feb9ca67-6670-483d-a895-22b031426a13",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f": {
- "id": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f",
- "type": "columns",
- "content": {},
- "isCodeManaged": false,
- "position": 0,
- "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "feb9ca67-6670-483d-a895-22b031426a13": {
- "id": "feb9ca67-6670-483d-a895-22b031426a13",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "3b325899-e560-40ea-ba54-9c55967af1e3": {
- "id": "3b325899-e560-40ea-ba54-9c55967af1e3",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "a0cd99db-0cbe-40ca-b9cb-b1670ec60dd8": {
- "id": "a0cd99db-0cbe-40ca-b9cb-b1670ec60dd8",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "5dcd137b-76bd-4a5f-ae5c-5b629035500e": {
- "id": "5dcd137b-76bd-4a5f-ae5c-5b629035500e",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 3,
- "parentId": "1c05b2e7-3a31-40dd-b6b8-77ded7c6bc0f",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "6a81f847-4d1d-4110-9cc1-12c716150e66": {
- "id": "6a81f847-4d1d-4110-9cc1-12c716150e66",
- "type": "metric",
- "content": {
- "metricValue": "@{metrics.average_length}cm",
- "name": "Average length",
- "note": "@{metrics.average_length_note}",
- "description": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "3b325899-e560-40ea-ba54-9c55967af1e3",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "8e54e9d2-a7c8-4f74-897f-fa5791cd82da": {
- "id": "8e54e9d2-a7c8-4f74-897f-fa5791cd82da",
- "type": "metric",
- "content": {
- "metricValue": "@{metrics.average_bmi}",
- "name": "Average BMI",
- "note": "@{metrics.average_bmi_note}",
- "description": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "a0cd99db-0cbe-40ca-b9cb-b1670ec60dd8",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "07f50628-4679-48a8-9a5d-07dcaf171afb": {
- "id": "07f50628-4679-48a8-9a5d-07dcaf171afb",
- "type": "metric",
- "content": {
- "metricValue": "@{metrics.diversity}",
- "name": "Diversity Index",
- "description": "",
- "note": "@{metrics.diversity_note}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "5dcd137b-76bd-4a5f-ae5c-5b629035500e",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "4cca0893-5ad7-4152-b805-5c87babc4dee": {
- "id": "4cca0893-5ad7-4152-b805-5c87babc4dee",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "c6392876-7cfd-4680-8725-b04f43ff294f",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "23bc1387-26ed-4ff2-8565-b027c2960c3c": {
- "id": "23bc1387-26ed-4ff2-8565-b027c2960c3c",
- "type": "page",
- "content": {
- "key": "story",
- "buttonColor": "#242424",
- "buttonTextColor": "#ffffff",
- "containerBackgroundColor": "#4F4F4F",
- "emptinessColor": "#333333",
- "primaryTextColor": "#ffffff",
- "separatorColor": "rgba(0, 0, 0, 0.2)"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "root",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "1d195388-35a3-43e1-b825-1d263b100a28": {
- "id": "1d195388-35a3-43e1-b825-1d263b100a28",
- "type": "header",
- "content": {
- "text": "HACKER PIGEONS"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "23bc1387-26ed-4ff2-8565-b027c2960c3c",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "771dc336-69b2-400e-9ea3-e881e2332c9d": {
- "id": "771dc336-69b2-400e-9ea3-e881e2332c9d",
- "type": "section",
- "content": {
- "title": "The story"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "dfaae7f9-db20-4f70-a376-919bdc7b6010",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "9c77aee4-e2a0-4e8b-9c2b-377f939bb51e": {
- "id": "9c77aee4-e2a0-4e8b-9c2b-377f939bb51e",
- "type": "text",
- "content": {
- "text": "@{story.text}"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "771dc336-69b2-400e-9ea3-e881e2332c9d"
- },
- "90fbfa9d-3178-4fc2-b445-c31e1acfa6a7": {
- "id": "90fbfa9d-3178-4fc2-b445-c31e1acfa6a7",
- "type": "button",
- "content": {
- "text": "Go back to the main page",
- "icon": "arrow_back"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "9bb8a686-7013-4af7-a89e-d89c7754120d",
- "handlers": {
- "click": "$goToPage_main"
- },
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "8fe33adf-a5ea-4c7a-8d1d-59cc4dc14f05": {
- "id": "8fe33adf-a5ea-4c7a-8d1d-59cc4dc14f05",
- "type": "columns",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "23bc1387-26ed-4ff2-8565-b027c2960c3c",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "7402263c-cb8b-412d-b170-e6dc6ffcb706": {
- "id": "7402263c-cb8b-412d-b170-e6dc6ffcb706",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "8fe33adf-a5ea-4c7a-8d1d-59cc4dc14f05",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "dfaae7f9-db20-4f70-a376-919bdc7b6010": {
- "id": "dfaae7f9-db20-4f70-a376-919bdc7b6010",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "8fe33adf-a5ea-4c7a-8d1d-59cc4dc14f05",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "5bc38721-8b48-43d5-a454-ee5ebe713a4c": {
- "id": "5bc38721-8b48-43d5-a454-ee5ebe713a4c",
- "type": "section",
- "content": {
- "title": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "7402263c-cb8b-412d-b170-e6dc6ffcb706"
- },
- "42ab5c3d-21fc-4e88-befd-33e52fd15e8b": {
- "id": "42ab5c3d-21fc-4e88-befd-33e52fd15e8b",
- "type": "image",
- "content": {
- "src": "static/pigeon1.jpg",
- "caption": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "5bc38721-8b48-43d5-a454-ee5ebe713a4c"
- },
- "9bb8a686-7013-4af7-a89e-d89c7754120d": {
- "id": "9bb8a686-7013-4af7-a89e-d89c7754120d",
- "type": "horizontalstack",
- "content": {
- "contentHAlign": "start"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "771dc336-69b2-400e-9ea3-e881e2332c9d",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "03f422ce-bc36-4000-8eb1-da1cc00948c9": {
- "id": "03f422ce-bc36-4000-8eb1-da1cc00948c9",
- "type": "button",
- "content": {
- "text": "Read the story",
- "icon": "library_books"
- },
- "isCodeManaged": false,
- "position": 5,
- "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76",
- "handlers": {
- "click": "$goToPage_story"
- },
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "2df56a4b-b6e7-423d-a7a1-5d23c77f65fa": {
- "id": "2df56a4b-b6e7-423d-a7a1-5d23c77f65fa",
- "type": "heading",
- "content": {
- "text": "Each page can have its own style",
- "alignment": ""
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "5bc38721-8b48-43d5-a454-ee5ebe713a4c"
- },
- "1272b52c-d97c-4c20-ba6b-19abe1ec0abc": {
- "id": "1272b52c-d97c-4c20-ba6b-19abe1ec0abc",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 0,
- "parentId": "771dc336-69b2-400e-9ea3-e881e2332c9d",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "77cb256b-ef12-4a55-a051-500497f41302": {
- "id": "77cb256b-ef12-4a55-a051-500497f41302",
- "type": "text",
- "content": {
- "text": "It's easy to switch between pages and it can be done from the frontend (via Writer Framework Builder) and from the backend (via Python)."
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "5bc38721-8b48-43d5-a454-ee5ebe713a4c",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "ed010441-0cac-4aa5-9e6f-97228e0c3536": {
- "id": "ed010441-0cac-4aa5-9e6f-97228e0c3536",
- "type": "button",
- "content": {
- "text": "Download this story",
- "icon": "download"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "9bb8a686-7013-4af7-a89e-d89c7754120d",
- "handlers": {
- "click": "handle_story_download"
- },
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "e1ax8ctt8lrao0e4": {
- "id": "e1ax8ctt8lrao0e4",
- "type": "tab",
- "content": {
- "name": "Pagination"
- },
- "isCodeManaged": false,
- "position": 3,
- "parentId": "ee919cd6-8153-4f34-8c6a-bfc1153df360",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "j3jkho6tb97u0onr": {
- "id": "j3jkho6tb97u0onr",
- "type": "repeater",
- "content": {
- "keyVariable": "itemId",
- "valueVariable": "item",
- "repeaterObject": "@{paginated_members}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "e1ax8ctt8lrao0e4",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "4wzaubf275w17gac": {
- "id": "4wzaubf275w17gac",
- "type": "section",
- "content": {
- "title": "@{item.name} \u2b50\ufe0f",
- "containerBackgroundColor": "#F5F5F9"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "j3jkho6tb97u0onr",
- "handlers": {},
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "19binb4yi70gesho": {
- "id": "19binb4yi70gesho",
- "type": "text",
- "content": {
- "text": "**Role:** @{item.role}\n",
- "useMarkdown": "yes"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "4wzaubf275w17gac"
- },
- "zfp1koasiuleygmz": {
- "id": "zfp1koasiuleygmz",
- "type": "pagination",
- "content": {
- "page": "@{paginated_members_page}",
- "pageSize": "@{paginated_members_page_size}",
- "totalItems": "@{paginated_members_total_items}",
- "pageSizeOptions": "1,2,5",
- "pageSizeShowAll": "no",
- "jumpTo": "no",
- "urlParam": "no"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "e1ax8ctt8lrao0e4",
- "handlers": {
- "wf-change-page": "handle_paginated_members_page_change",
- "wf-change-page-size": "handle_paginated_members_page_size_change"
- },
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "b27lw9ex8ig3x17p": {
- "id": "b27lw9ex8ig3x17p",
- "type": "tags",
- "content": {
- "tags": "{\n \"fiction\": \"fiction\",\n \"inspirational\": \"inspirational\",\n \"ai-generated\": \"ai-generated\"\n}",
- "seed": ""
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76",
- "visible": {
- "expression": true,
- "binding": "",
- "reversed": false
- }
- },
- "804e15bf-11a7-463d-8082-f46ea3acac1b": {
- "id": "804e15bf-11a7-463d-8082-f46ea3acac1b",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 3,
- "parentId": "9c30af6d-4ee5-4782-9169-0f361d67fa76"
- }
- }
-}
\ No newline at end of file
diff --git a/apps/pdg-tutorial/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl b/apps/pdg-tutorial/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl
new file mode 100644
index 000000000..5ffa37d55
--- /dev/null
+++ b/apps/pdg-tutorial/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl
@@ -0,0 +1,12 @@
+{"id": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "type": "page", "content": {"pageMode": "compact"}, "isCodeManaged": false, "position": 0, "parentId": "root", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf", "type": "header", "content": {"text": "PRODUCT DESCRIPTION GENERATOR"}, "isCodeManaged": false, "position": 0, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "wf7ucshlh1xd01rd", "type": "columns", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "wki2gol8f69jo2wr", "type": "column", "content": {"width": "1"}, "isCodeManaged": false, "position": 0, "parentId": "wf7ucshlh1xd01rd", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "dtueaw3s6jucxztj", "type": "column", "content": {"width": "2"}, "isCodeManaged": false, "position": 1, "parentId": "wf7ucshlh1xd01rd", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "9951wujx1y63miao", "type": "section", "content": {"title": ""}, "isCodeManaged": false, "position": 0, "parentId": "wki2gol8f69jo2wr", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "ot9efvpwoh7haksz", "type": "tabs", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "dtueaw3s6jucxztj", "handlers": {}}
+{"id": "kyvrec2azudr740n", "type": "message", "content": {"message": "@{message}"}, "isCodeManaged": false, "position": 0, "parentId": "dtueaw3s6jucxztj", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "c8um3pjausohruax", "type": "textinput", "content": {"label": "Name"}, "isCodeManaged": false, "position": 0, "parentId": "9951wujx1y63miao", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}, "binding": {"eventType": "wf-change", "stateRef": "form.title"}}
+{"id": "s3aqi4bi8p4nc871", "type": "textinput", "content": {"label": "Description"}, "isCodeManaged": false, "position": 1, "parentId": "9951wujx1y63miao", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}, "binding": {"eventType": "wf-change", "stateRef": "form.description"}}
+{"id": "g9c82lcp1o8v0wof", "type": "button", "content": {"text": "Generate", "icon": "laps"}, "isCodeManaged": false, "position": 3, "parentId": "9951wujx1y63miao", "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "zg72wu4k9394ah9q", "type": "textinput", "content": {"label": "Keywords"}, "isCodeManaged": false, "position": 2, "parentId": "9951wujx1y63miao", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}, "binding": {"eventType": "wf-change", "stateRef": "form.keywords"}}
diff --git a/apps/pdg-tutorial/.wf/components-root.jsonl b/apps/pdg-tutorial/.wf/components-root.jsonl
new file mode 100644
index 000000000..792cb329b
--- /dev/null
+++ b/apps/pdg-tutorial/.wf/components-root.jsonl
@@ -0,0 +1 @@
+{"id": "root", "type": "root", "content": {"appName": "Product Description Generator"}, "isCodeManaged": false, "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
\ No newline at end of file
diff --git a/apps/pdg-tutorial/.wf/metadata.json b/apps/pdg-tutorial/.wf/metadata.json
new file mode 100644
index 000000000..1f76abe5a
--- /dev/null
+++ b/apps/pdg-tutorial/.wf/metadata.json
@@ -0,0 +1,3 @@
+{
+ "writer_version": "0.7.0rc2"
+}
\ No newline at end of file
diff --git a/apps/pdg-tutorial/ui.json b/apps/pdg-tutorial/ui.json
deleted file mode 100644
index ecff21b01..000000000
--- a/apps/pdg-tutorial/ui.json
+++ /dev/null
@@ -1,169 +0,0 @@
-{
- "metadata": {
- "writer_version": "0.6.0rc3"
- },
- "components": {
- "root": {
- "id": "root",
- "type": "root",
- "content": {
- "appName": "Product Description Generator"
- },
- "isCodeManaged": false,
- "position": 0,
- "handlers": {},
- "visible": true
- },
- "c0f99a9e-5004-4e75-a6c6-36f17490b134": {
- "id": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "type": "page",
- "content": {
- "pageMode": "compact"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "root",
- "handlers": {},
- "visible": true
- },
- "bebc5fe9-63a7-46a7-b0fa-62303555cfaf": {
- "id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf",
- "type": "header",
- "content": {
- "text": "PRODUCT DESCRIPTION GENERATOR"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "handlers": {},
- "visible": true
- },
- "wf7ucshlh1xd01rd": {
- "id": "wf7ucshlh1xd01rd",
- "type": "columns",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "handlers": {},
- "visible": true
- },
- "wki2gol8f69jo2wr": {
- "id": "wki2gol8f69jo2wr",
- "type": "column",
- "content": {
- "width": "1"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "wf7ucshlh1xd01rd",
- "handlers": {},
- "visible": true
- },
- "dtueaw3s6jucxztj": {
- "id": "dtueaw3s6jucxztj",
- "type": "column",
- "content": {
- "width": "2"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "wf7ucshlh1xd01rd",
- "handlers": {},
- "visible": true
- },
- "9951wujx1y63miao": {
- "id": "9951wujx1y63miao",
- "type": "section",
- "content": {
- "title": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "wki2gol8f69jo2wr",
- "handlers": {},
- "visible": true
- },
- "ot9efvpwoh7haksz": {
- "id": "ot9efvpwoh7haksz",
- "type": "tabs",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "dtueaw3s6jucxztj",
- "handlers": {}
- },
- "kyvrec2azudr740n": {
- "id": "kyvrec2azudr740n",
- "type": "message",
- "content": {
- "message": "@{message}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "dtueaw3s6jucxztj",
- "handlers": {},
- "visible": true
- },
- "c8um3pjausohruax": {
- "id": "c8um3pjausohruax",
- "type": "textinput",
- "content": {
- "label": "Name"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "9951wujx1y63miao",
- "handlers": {},
- "visible": true,
- "binding": {
- "eventType": "wf-change",
- "stateRef": "form.title"
- }
- },
- "s3aqi4bi8p4nc871": {
- "id": "s3aqi4bi8p4nc871",
- "type": "textinput",
- "content": {
- "label": "Description"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "9951wujx1y63miao",
- "handlers": {},
- "visible": true,
- "binding": {
- "eventType": "wf-change",
- "stateRef": "form.description"
- }
- },
- "g9c82lcp1o8v0wof": {
- "id": "g9c82lcp1o8v0wof",
- "type": "button",
- "content": {
- "text": "Generate",
- "icon": "laps"
- },
- "isCodeManaged": false,
- "position": 3,
- "parentId": "9951wujx1y63miao",
- "visible": true
- },
- "zg72wu4k9394ah9q": {
- "id": "zg72wu4k9394ah9q",
- "type": "textinput",
- "content": {
- "label": "Keywords"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "9951wujx1y63miao",
- "handlers": {},
- "visible": true,
- "binding": {
- "eventType": "wf-change",
- "stateRef": "form.keywords"
- }
- }
- }
-}
\ No newline at end of file
diff --git a/apps/quickstart/.wf/components-page-0-e8e4m9mx50wfpdty.jsonl b/apps/quickstart/.wf/components-page-0-e8e4m9mx50wfpdty.jsonl
new file mode 100644
index 000000000..a39ae6c61
--- /dev/null
+++ b/apps/quickstart/.wf/components-page-0-e8e4m9mx50wfpdty.jsonl
@@ -0,0 +1,13 @@
+{"id": "e8e4m9mx50wfpdty", "type": "page", "content": {}, "parentId": "root", "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "g7hhwdug524j0fql", "type": "header", "content": {"text": "@{my_app.title}"}, "parentId": "e8e4m9mx50wfpdty", "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "j8tmgh7pgdk1nzfb", "type": "columns", "content": {}, "parentId": "7hlk8jwfhvz29rbc", "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "t3zfxwztd4cozu6v", "type": "column", "content": {"width": "0.5"}, "parentId": "j8tmgh7pgdk1nzfb", "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "0vruexh3b8ajbuw9", "type": "column", "content": {"width": "1"}, "parentId": "j8tmgh7pgdk1nzfb", "position": 1, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "yb81pneakk4w7esg", "type": "sliderinput", "content": {"label": "Number of groups", "minValue": "2", "maxValue": "10", "stepSize": "1"}, "parentId": "t3zfxwztd4cozu6v", "position": 0, "handlers": {"wf-number-change": "update"}, "binding": {"eventType": "wf-number-change", "stateRef": "number_of_groups"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "27wp270aghglmgx2", "type": "plotlygraph", "content": {"spec": "@{figure}"}, "parentId": "0vruexh3b8ajbuw9", "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "b4ope7gynk5onxnq", "type": "sliderinput", "content": {"label": "Number of points", "minValue": "50", "maxValue": "1000", "stepSize": "1"}, "parentId": "t3zfxwztd4cozu6v", "position": 1, "handlers": {"wf-number-change": "update"}, "binding": {"eventType": "wf-number-change", "stateRef": "number_of_points"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "v75sjhqjgpw0g0a7", "type": "message", "content": {"message": "@{message}"}, "parentId": "g7hhwdug524j0fql", "position": 0, "handlers": {}, "visible": {"expression": "custom", "binding": "message", "reversed": false}}
+{"id": "tnooah1ico3nylvu", "type": "dropdowninput", "content": {"label": "Type", "options": "{\"ovr\": \"One vs Rest\", \"multinomial\": \"Multinomial\"}", "cssClasses": ""}, "parentId": "t3zfxwztd4cozu6v", "position": 3, "handlers": {"wf-option-change": "update"}, "binding": {"eventType": "wf-option-change", "stateRef": "multi_class"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "yfyr3y9xdllskii4", "type": "sliderinput", "content": {"label": "Cluster deviation", "minValue": "0", "maxValue": "10", "stepSize": "0.1"}, "parentId": "t3zfxwztd4cozu6v", "position": 2, "handlers": {"wf-number-change": "update"}, "binding": {"eventType": "wf-number-change", "stateRef": "cluster_std"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "nfkazqjoivq5b4k9", "type": "button", "content": {"text": "Regenerate"}, "parentId": "t3zfxwztd4cozu6v", "position": 4, "handlers": {"wf-click": "update"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "7hlk8jwfhvz29rbc", "type": "section", "content": {"title": ""}, "parentId": "e8e4m9mx50wfpdty", "position": 1, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
diff --git a/apps/quickstart/.wf/components-root.jsonl b/apps/quickstart/.wf/components-root.jsonl
new file mode 100644
index 000000000..41dd67afd
--- /dev/null
+++ b/apps/quickstart/.wf/components-root.jsonl
@@ -0,0 +1 @@
+{"id": "root", "type": "root", "content": {"appName": "Hello"}, "parentId": null, "position": 0}
\ No newline at end of file
diff --git a/apps/quickstart/.wf/metadata.json b/apps/quickstart/.wf/metadata.json
new file mode 100644
index 000000000..1f76abe5a
--- /dev/null
+++ b/apps/quickstart/.wf/metadata.json
@@ -0,0 +1,3 @@
+{
+ "writer_version": "0.7.0rc2"
+}
\ No newline at end of file
diff --git a/apps/quickstart/ui.json b/apps/quickstart/ui.json
deleted file mode 100644
index efe6ca0b4..000000000
--- a/apps/quickstart/ui.json
+++ /dev/null
@@ -1,192 +0,0 @@
-{
- "metadata": {
- "writer_version": "0.3.0"
- },
- "components": {
- "root": {
- "id": "root",
- "type": "root",
- "content": {
- "appName": "Hello"
- },
- "parentId": null,
- "position": 0
- },
- "e8e4m9mx50wfpdty": {
- "id": "e8e4m9mx50wfpdty",
- "type": "page",
- "content": {},
- "parentId": "root",
- "position": 0,
- "handlers": {},
- "visible": true
- },
- "g7hhwdug524j0fql": {
- "id": "g7hhwdug524j0fql",
- "type": "header",
- "content": {
- "text": "@{my_app.title}"
- },
- "parentId": "e8e4m9mx50wfpdty",
- "position": 0,
- "handlers": {},
- "visible": true
- },
- "j8tmgh7pgdk1nzfb": {
- "id": "j8tmgh7pgdk1nzfb",
- "type": "columns",
- "content": {},
- "parentId": "7hlk8jwfhvz29rbc",
- "position": 0,
- "handlers": {},
- "visible": true
- },
- "t3zfxwztd4cozu6v": {
- "id": "t3zfxwztd4cozu6v",
- "type": "column",
- "content": {
- "width": "0.5"
- },
- "parentId": "j8tmgh7pgdk1nzfb",
- "position": 0,
- "handlers": {},
- "visible": true
- },
- "0vruexh3b8ajbuw9": {
- "id": "0vruexh3b8ajbuw9",
- "type": "column",
- "content": {
- "width": "1"
- },
- "parentId": "j8tmgh7pgdk1nzfb",
- "position": 1,
- "handlers": {},
- "visible": true
- },
- "yb81pneakk4w7esg": {
- "id": "yb81pneakk4w7esg",
- "type": "sliderinput",
- "content": {
- "label": "Number of groups",
- "minValue": "2",
- "maxValue": "10",
- "stepSize": "1"
- },
- "parentId": "t3zfxwztd4cozu6v",
- "position": 0,
- "handlers": {
- "wf-number-change": "update"
- },
- "binding": {
- "eventType": "wf-number-change",
- "stateRef": "number_of_groups"
- },
- "visible": true
- },
- "27wp270aghglmgx2": {
- "id": "27wp270aghglmgx2",
- "type": "plotlygraph",
- "content": {
- "spec": "@{figure}"
- },
- "parentId": "0vruexh3b8ajbuw9",
- "position": 0,
- "handlers": {},
- "visible": true
- },
- "b4ope7gynk5onxnq": {
- "id": "b4ope7gynk5onxnq",
- "type": "sliderinput",
- "content": {
- "label": "Number of points",
- "minValue": "50",
- "maxValue": "1000",
- "stepSize": "1"
- },
- "parentId": "t3zfxwztd4cozu6v",
- "position": 1,
- "handlers": {
- "wf-number-change": "update"
- },
- "binding": {
- "eventType": "wf-number-change",
- "stateRef": "number_of_points"
- },
- "visible": true
- },
- "v75sjhqjgpw0g0a7": {
- "id": "v75sjhqjgpw0g0a7",
- "type": "message",
- "content": {
- "message": "@{message}"
- },
- "parentId": "g7hhwdug524j0fql",
- "position": 0,
- "handlers": {},
- "visible": "message"
- },
- "tnooah1ico3nylvu": {
- "id": "tnooah1ico3nylvu",
- "type": "dropdowninput",
- "content": {
- "label": "Type",
- "options": "{\"ovr\": \"One vs Rest\", \"multinomial\": \"Multinomial\"}",
- "cssClasses": ""
- },
- "parentId": "t3zfxwztd4cozu6v",
- "position": 3,
- "handlers": {
- "wf-option-change": "update"
- },
- "binding": {
- "eventType": "wf-option-change",
- "stateRef": "multi_class"
- },
- "visible": true
- },
- "yfyr3y9xdllskii4": {
- "id": "yfyr3y9xdllskii4",
- "type": "sliderinput",
- "content": {
- "label": "Cluster deviation",
- "minValue": "0",
- "maxValue": "10",
- "stepSize": "0.1"
- },
- "parentId": "t3zfxwztd4cozu6v",
- "position": 2,
- "handlers": {
- "wf-number-change": "update"
- },
- "binding": {
- "eventType": "wf-number-change",
- "stateRef": "cluster_std"
- },
- "visible": true
- },
- "nfkazqjoivq5b4k9": {
- "id": "nfkazqjoivq5b4k9",
- "type": "button",
- "content": {
- "text": "Regenerate"
- },
- "parentId": "t3zfxwztd4cozu6v",
- "position": 4,
- "handlers": {
- "wf-click": "update"
- },
- "visible": true
- },
- "7hlk8jwfhvz29rbc": {
- "id": "7hlk8jwfhvz29rbc",
- "type": "section",
- "content": {
- "title": ""
- },
- "parentId": "e8e4m9mx50wfpdty",
- "position": 1,
- "handlers": {},
- "visible": true
- }
- }
-}
\ No newline at end of file
diff --git a/apps/text-demo/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl b/apps/text-demo/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl
new file mode 100644
index 000000000..ddf306200
--- /dev/null
+++ b/apps/text-demo/.wf/components-page-0-c0f99a9e-5004-4e75-a6c6-36f17490b134.jsonl
@@ -0,0 +1,10 @@
+{"id": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "type": "page", "content": {"pageMode": "compact"}, "isCodeManaged": false, "position": 0, "parentId": "root", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf", "type": "header", "content": {"text": "SOCIAL POST GENERATOR"}, "isCodeManaged": false, "position": 0, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "q237uluwl8idg8is", "type": "text", "content": {"text": "@{posts}", "useMarkdown": "yes"}, "isCodeManaged": false, "position": 2, "parentId": "4k8f6ju68i8qej2s", "handlers": {}, "visible": {"expression": "custom", "binding": "", "reversed": false}}
+{"id": "xszjpksyo1sfdu0c", "type": "section", "content": {"title": "", "containerBackgroundColor": "#EDE2FF", "accentColor": "#721CC9"}, "isCodeManaged": false, "position": 1, "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "3fbhifcljb3mqnpv", "type": "textinput", "content": {"label": "Generate social posts about..."}, "isCodeManaged": false, "position": 0, "parentId": "xszjpksyo1sfdu0c", "visible": {"expression": true, "binding": "", "reversed": false}, "binding": {"eventType": "wf-change", "stateRef": "topic"}}
+{"id": "v8o8h5estbx22uw7", "type": "button", "content": {"text": "Generate posts", "icon": "arrow_forward"}, "isCodeManaged": false, "position": 1, "parentId": "xszjpksyo1sfdu0c", "handlers": {"wf-click": "handle_button_click"}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "hhmi0u8nksz57cbc", "type": "message", "content": {"message": "@{message}", "loadingColor": "#D4FFF2"}, "isCodeManaged": false, "position": 2, "parentId": "xszjpksyo1sfdu0c", "handlers": {}, "visible": {"expression": "custom", "binding": "message", "reversed": false}}
+{"id": "4k8f6ju68i8qej2s", "type": "section", "content": {"title": "", "containerBackgroundColor": "#F6EFFD", "containerShadow": "none"}, "isCodeManaged": false, "position": 3, "parentId": "xszjpksyo1sfdu0c", "handlers": {}, "visible": {"expression": "custom", "binding": "posts", "reversed": false}}
+{"id": "o1753ot0w2n4704o", "type": "tags", "content": {"tags": "@{tags}"}, "isCodeManaged": false, "position": 0, "parentId": "4k8f6ju68i8qej2s", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
+{"id": "ywzboz2fup220b1d", "type": "separator", "content": {}, "isCodeManaged": false, "position": 1, "parentId": "4k8f6ju68i8qej2s", "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
diff --git a/apps/text-demo/.wf/components-root.jsonl b/apps/text-demo/.wf/components-root.jsonl
new file mode 100644
index 000000000..015905c99
--- /dev/null
+++ b/apps/text-demo/.wf/components-root.jsonl
@@ -0,0 +1 @@
+{"id": "root", "type": "root", "content": {"appName": "Social Post Generator Demo", "cssClasses": ""}, "isCodeManaged": false, "position": 0, "handlers": {}, "visible": {"expression": true, "binding": "", "reversed": false}}
\ No newline at end of file
diff --git a/apps/text-demo/.wf/metadata.json b/apps/text-demo/.wf/metadata.json
new file mode 100644
index 000000000..1f76abe5a
--- /dev/null
+++ b/apps/text-demo/.wf/metadata.json
@@ -0,0 +1,3 @@
+{
+ "writer_version": "0.7.0rc2"
+}
\ No newline at end of file
diff --git a/apps/text-demo/ui.json b/apps/text-demo/ui.json
deleted file mode 100644
index f5b5c5e8b..000000000
--- a/apps/text-demo/ui.json
+++ /dev/null
@@ -1,149 +0,0 @@
-{
- "metadata": {
- "writer_version": "0.6.0rc4"
- },
- "components": {
- "root": {
- "id": "root",
- "type": "root",
- "content": {
- "appName": "Social Post Generator Demo",
- "cssClasses": ""
- },
- "isCodeManaged": false,
- "position": 0,
- "handlers": {},
- "visible": true
- },
- "c0f99a9e-5004-4e75-a6c6-36f17490b134": {
- "id": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "type": "page",
- "content": {
- "pageMode": "compact"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "root",
- "handlers": {},
- "visible": true
- },
- "bebc5fe9-63a7-46a7-b0fa-62303555cfaf": {
- "id": "bebc5fe9-63a7-46a7-b0fa-62303555cfaf",
- "type": "header",
- "content": {
- "text": "SOCIAL POST GENERATOR"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "handlers": {},
- "visible": true
- },
- "q237uluwl8idg8is": {
- "id": "q237uluwl8idg8is",
- "type": "text",
- "content": {
- "text": "@{posts}",
- "useMarkdown": "yes"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "4k8f6ju68i8qej2s",
- "handlers": {},
- "visible": ""
- },
- "xszjpksyo1sfdu0c": {
- "id": "xszjpksyo1sfdu0c",
- "type": "section",
- "content": {
- "title": "",
- "containerBackgroundColor": "#EDE2FF",
- "accentColor": "#721CC9"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "c0f99a9e-5004-4e75-a6c6-36f17490b134",
- "handlers": {},
- "visible": true
- },
- "3fbhifcljb3mqnpv": {
- "id": "3fbhifcljb3mqnpv",
- "type": "textinput",
- "content": {
- "label": "Generate social posts about..."
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "xszjpksyo1sfdu0c",
- "visible": true,
- "binding": {
- "eventType": "wf-change",
- "stateRef": "topic"
- }
- },
- "v8o8h5estbx22uw7": {
- "id": "v8o8h5estbx22uw7",
- "type": "button",
- "content": {
- "text": "Generate posts",
- "icon": "arrow_forward"
- },
- "isCodeManaged": false,
- "position": 1,
- "parentId": "xszjpksyo1sfdu0c",
- "handlers": {
- "wf-click": "handle_button_click"
- },
- "visible": true
- },
- "hhmi0u8nksz57cbc": {
- "id": "hhmi0u8nksz57cbc",
- "type": "message",
- "content": {
- "message": "@{message}",
- "loadingColor": "#D4FFF2"
- },
- "isCodeManaged": false,
- "position": 2,
- "parentId": "xszjpksyo1sfdu0c",
- "handlers": {},
- "visible": "message"
- },
- "4k8f6ju68i8qej2s": {
- "id": "4k8f6ju68i8qej2s",
- "type": "section",
- "content": {
- "title": "",
- "containerBackgroundColor": "#F6EFFD",
- "containerShadow": "none"
- },
- "isCodeManaged": false,
- "position": 3,
- "parentId": "xszjpksyo1sfdu0c",
- "handlers": {},
- "visible": "posts"
- },
- "o1753ot0w2n4704o": {
- "id": "o1753ot0w2n4704o",
- "type": "tags",
- "content": {
- "tags": "@{tags}"
- },
- "isCodeManaged": false,
- "position": 0,
- "parentId": "4k8f6ju68i8qej2s",
- "handlers": {},
- "visible": true
- },
- "ywzboz2fup220b1d": {
- "id": "ywzboz2fup220b1d",
- "type": "separator",
- "content": {},
- "isCodeManaged": false,
- "position": 1,
- "parentId": "4k8f6ju68i8qej2s",
- "handlers": {},
- "visible": true
- }
- }
-}
\ No newline at end of file
diff --git a/docs/framework/authentication.mdx b/docs/framework/authentication.mdx
index 63e19bce5..f7f6d4062 100644
--- a/docs/framework/authentication.mdx
+++ b/docs/framework/authentication.mdx
@@ -9,6 +9,10 @@ The Writer Framework authentication module allows you to restrict access to your
trigger authentication for certain pages exclusively.
+
+ Static assets from Writer Framework exposed through `/static` and `/extensions` endpoints are not protected behind Authentication.
+
+
## Use Basic Auth
Basic Auth is a simple authentication method that uses a username and password. Authentication configuration is done in the [server_setup.py module](/framework/custom-server).
@@ -134,6 +138,21 @@ writer.serve.register_auth(oidc)
+### App static assets
+
+Static assets in your application are inaccessible. You can use the `app_static_public` parameter to allow their usage.
+When `app_static_public` is set to `True`, the static assets in your application are accessible without authentication.
+
+```python
+oidc = writer.auth.Auth0(
+ client_id="xxxxxxx",
+ client_secret="xxxxxxxxxxxxx",
+ domain="xxx-xxxxx.eu.auth0.com",
+ host_url=os.getenv('HOST_URL', "http://localhost:5000"),
+ app_static_public=True
+)
+```
+
## User information in event handler
When the `user_info` route is configured, user information will be accessible
diff --git a/docs/framework/backend-driven-ui.mdx b/docs/framework/backend-driven-ui.mdx
index a1d94328b..80b231851 100644
--- a/docs/framework/backend-driven-ui.mdx
+++ b/docs/framework/backend-driven-ui.mdx
@@ -4,7 +4,7 @@ title: "Backend-driven UI"
Framework facilitates backend-initiated user interface modifications. These changes are made possible through **Code-Managed Components** (CMCs), distinct from the *Builder-Managed Components* (BMCs).
-CMCs, unlike BMCs, are dynamically created and modified via back-end code, and cannot be edited (but still can be viewed) within the application builder. It's important to also note that CMCs do not persist in your application's `ui.json` file and exist only during the application runtime, supporting dynamic UI adjustments.
+CMCs, unlike BMCs, are dynamically created and modified via back-end code, and cannot be edited (but still can be viewed) within the application builder. It's important to also note that CMCs do not persist in your application's files and exist only during the application runtime, supporting dynamic UI adjustments.
To summarise:
@@ -12,12 +12,12 @@ To summarise:
**CMC** – Code-Managed Component
- created via **application back-end**;
- **cannot be edited** in builder;
-- is **not saved** to `ui.json`.
+- is **not saved** to `.wf/components-*.jsonl`.
**BMC** – Builder-Managed Component
- created via **builder**;
- **can be edited** in builder;
-- is **saved** to `ui.json`.
+- is **saved** to `.wf/components-*.jsonl`.
## UI manager
diff --git a/docs/framework/builder-basics.mdx b/docs/framework/builder-basics.mdx
index 78489d427..e44369400 100644
--- a/docs/framework/builder-basics.mdx
+++ b/docs/framework/builder-basics.mdx
@@ -2,7 +2,7 @@
title: "Builder basics"
---
-Framework Builder works as an overlay of the running app; you edit your app while it's running. It gives you an accurate representation of what the app will look like and how it'll behave, without the need to constantly preview it. Changes to the user interface are automatically saved to `ui.json`.
+Framework Builder works as an overlay of the running app; you edit your app while it's running. It gives you an accurate representation of what the app will look like and how it'll behave, without the need to constantly preview it. Changes to the user interface are automatically saved into `.wf/` folders.
## Modes
diff --git a/docs/framework/custom-components.mdx b/docs/framework/custom-components.mdx
index 23152de51..5ce899008 100644
--- a/docs/framework/custom-components.mdx
+++ b/docs/framework/custom-components.mdx
@@ -7,10 +7,10 @@ It's possible to extend Framework with custom component templates.
They're developed using Vue 3 and TypeScript. Once transpiled, they can be used by copying them to the `extensions/` folder of any project.
- Custom components behave exactly like built-in ones. They are just as
- performant, can contain other components, and offer the same the Builder
- experience. They only differ from built-in components in the way that they're
- bundled and imported.
+ Custom components behave exactly like built-in ones. They are just as
+ performant, can contain other components, and offer the same the Builder
+ experience. They only differ from built-in components in the way that they're
+ bundled and imported.
## Architecture
@@ -101,39 +101,41 @@ The code above will make Bubble Message available in the Builder.
### Run a local server
-
- To get started, clone the [Framework
- repository](https://github.com/writer/writer-framework) from GitHub.
-
-
- To develop custom templates in a developer-friendly way, ensure you have a
- front-end development server with instant reload capabilities. The front-end
- code for Framework is located in the `ui` folder. With Node and npm
- installed on your system, run `npm install` to install dependencies. Then,
- start the server with support for custom component templates using `npm run
- custom.dev`. ```sh cd ui npm install # "custom.dev" links templates in
- "custom_components/" # "dev" runs the server without them npm run custom.dev
- ```
-
-
- The command `npm run custom.dev` starts a front-end server, which requires a
- back-end to function fully. Start Framework via command line, specifying the
- option `--port 5000`, to provide a back-end on that port. It's recommended
- to create a new app for testing the template you're developing. ```sh writer
- create customtester writer edit customtester --port 5000 ```
-
-
- You should now be able to access Framework via the URL provided by Vite,
- e.g. `http://localhost:5174`. In the Builder's _Toolkit_, you should see the
- sample component, _Balloon Message_. Add it to your tester application.
-
+
+ To get started, clone the [Framework
+ repository](https://github.com/writer/writer-framework) from GitHub.
+
+
+ To develop custom templates in a developer-friendly way, ensure you have a
+ front-end development server with instant reload capabilities. The front-end
+ code for Framework is located in the `ui` folder. With Node and npm
+ installed on your system, run `npm install` to install dependencies. Then,
+ start the server with support for custom component templates using `npm run
+ custom.dev`.
+
+ ```sh cd ui npm install # "custom.dev" links templates in
+ "custom_components/" # "dev" runs the server without them npm run custom.dev
+ ```
+
+
+ The command `npm run custom.dev` starts a front-end server, which requires a
+ back-end to function fully. Start Framework via command line, specifying the
+ option `--port 5000`, to provide a back-end on that port. It's recommended
+ to create a new app for testing the template you're developing. ```sh writer
+ create customtester writer edit customtester --port 5000 ```
+
+
+ You should now be able to access Framework via the URL provided by Vite,
+ e.g. `http://localhost:5174`. In the Builder's _Toolkit_, you should see the
+ sample component, _Balloon Message_. Add it to your tester application.
+
### Create a new component
- You can also have a look at the built-in component templates, since their
- syntax is equivalent. They can be found in the `ui/src/components/` folder.
+ You can also have a look at the built-in component templates, since their
+ syntax is equivalent. They can be found in the `ui/src/components/` folder.
Go to `ui/src/custom_components/` and open the Vue single-file components, i.e. the
`.vue` files. These files contain comments that will help you get started. Try editing
@@ -154,8 +156,8 @@ import BubbleMessageAdvanced from "./BubbleMessageAdvanced.vue";
// Export an object with the ids and the templates as default
export default {
- bubblemessage: BubbleMessage,
- bubblemessageadvanced: BubbleMessageAdvanced,
+ bubblemessage: BubbleMessage,
+ bubblemessageadvanced: BubbleMessageAdvanced,
};
```
@@ -163,13 +165,18 @@ A single or multiple templates can be specified. Take into account that they wil
## Bundling templates
-Execute `npm run custom.build`, this will generate the output `.js` and `.css` files into `ui/custom_components_dist`.
+Execute `npm run custom.build` into `src/ui`, this will generate the output `.js` and `.css` files into `./custom_components_dist`.
```sh
# "build" builds the entire front-end
# "custom.build" only builds the custom templates
+npm run custom.check # Optional: checks certain issues on custom components
npm run custom.build
```
-Collect the files from `ui/custom_components_dist` and pack them in a folder such as `my_custom_bubbles`. The folder containing the generated files, e.g. `my_custom_bubbles`, can now be placed in the `extensions/` folder of any Framework project. It'll be automatically detected during server startup.
+Collect the files from `./custom_components_dist` and pack them in a folder such as `my_custom_bubbles`. The folder containing the generated files, e.g. `my_custom_bubbles`, can now be placed in the `extensions/` folder of any Framework project. It'll be automatically detected during server startup.
+
+
+The `custom.check` command is optional, but it's recommended to run it before building the custom components. It checks for common issues in the custom components, such as invalid key declaration, ...
+
diff --git a/docs/framework/custom-server.mdx b/docs/framework/custom-server.mdx
index a912d971b..730a74111 100644
--- a/docs/framework/custom-server.mdx
+++ b/docs/framework/custom-server.mdx
@@ -7,7 +7,7 @@ Framework uses Uvicorn and serves the app in the root path i.e. `/`. If you need
## Configure webserver
You can tune your server by adding a `server_setup.py` file to the root
-of your application, next to the `main.py` and `ui.json` files.
+of your application, next to the `main.py` files.
This file is executed before starting writer. It allows you to configure [authentication](./authentication.md),
add your own routes and middlewares on FastAPI.
diff --git a/docs/framework/deploy-with-docker.mdx b/docs/framework/deploy-with-docker.mdx
index 01358def5..2eaac11ce 100644
--- a/docs/framework/deploy-with-docker.mdx
+++ b/docs/framework/deploy-with-docker.mdx
@@ -22,7 +22,7 @@ You can use Docker to deploy Framework anywhere. If you're an experienced Docker
-A Dockerfile is a file with instructions that tell Docker how to build your image. It must be named `Dockerfile`. You can use the following as-is, or as a starting point. It should be saved in your app's folder, together with `main.py` and `ui.json`.
+A Dockerfile is a file with instructions that tell Docker how to build your image. It must be named `Dockerfile`. You can use the following as-is, or as a starting point. It should be saved in your app's folder, together with `main.py` and `.wf/`.
```docker
FROM python:3.10-bullseye
diff --git a/docs/framework/quickstart.mdx b/docs/framework/quickstart.mdx
index d309e2ec6..d85a08709 100644
--- a/docs/framework/quickstart.mdx
+++ b/docs/framework/quickstart.mdx
@@ -39,7 +39,7 @@ writer create testapp
A Framework app is a folder with the following items.
1. `main.py` - The entry point for the app. You can import anything you need from here.
-2. `ui.json` - Contains the UI component declarations. Maintained by the Writer Framework's visual editor.
+2. `.wf/` - This folder contains the UI component declarations. Maintained by the Writer Framework's visual editor.
3. `static/` - This folder contains front-end static files which you might want to distribute with your app. For example, images and stylesheets.
## Start the editor
@@ -90,4 +90,4 @@ Writer provides a quick and fast way to deploy your apps via the [Writer cloud](
writer deploy
```
-You’ll be asked to enter your API key. To find your key, log in to your [AI Studio account](https://app.writer.com/aistudio) and either create a new framework app by going through the create app workflow or choose an existing framework app from your home screen. For other deployment options, see [Deploy with Docker](/framework/deploy-with-docker).
\ No newline at end of file
+You’ll be asked to enter your API key. To find your key, log in to your [AI Studio account](https://app.writer.com/aistudio) and either create a new framework app by going through the create app workflow or choose an existing framework app from your home screen. For other deployment options, see [Deploy with Docker](/framework/deploy-with-docker).
diff --git a/package.json b/package.json
index 2d749778c..2215771c0 100644
--- a/package.json
+++ b/package.json
@@ -29,8 +29,9 @@
"ui:build": "npm run -w writer-ui build",
"ui:preview": "npm run -w writer-ui preview",
"ui:custom.build": "npm run -w writer-ui custom.build",
+ "ui:custom.check": "npm run -w writer-ui custom.check",
"ui:lint": "npm run -w writer-ui lint",
- "ui:lint:ci": "npm run -w writer-ui lint:ci",
+ "ui:lint.ci": "npm run -w writer-ui lint.ci",
"docs:codegen": "npm run -w writer-docs codegen",
"docs:preview": "npm run -w writer-docs preview",
diff --git a/pyproject.toml b/pyproject.toml
index 2839baf24..0859e39dc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry]
name = "writer"
-version = "0.7.2"
+version = "0.7.5"
description = "An open-source, Python framework for building feature-rich apps that are fully integrated with the Writer platform."
authors = ["Writer, Inc."]
readme = "README.md"
diff --git a/src/ui/package.json b/src/ui/package.json
index 590dcfd78..aabcd24cd 100644
--- a/src/ui/package.json
+++ b/src/ui/package.json
@@ -7,10 +7,11 @@
"build": "vite build",
"preview": "vite preview --port 5050",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path ../../.gitignore --ignore-path .gitignore",
- "lint:ci": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --ignore-path ../../.gitignore --ignore-path .gitignore",
+ "lint.ci": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --ignore-path ../../.gitignore --ignore-path .gitignore",
"codegen": "node tools/generator.mjs",
"custom.dev": "vite --config vite.config.custom.ts",
"custom.build": "vite build --config vite.config.custom.ts",
+ "custom.check": "node tools/custom_check.mjs",
"storybook": "storybook dev -p 6006",
"storybook.build": "storybook build"
},
@@ -61,4 +62,4 @@
"eslint-plugin-storybook": "0.8.0",
"storybook": "8.0.5"
}
-}
\ No newline at end of file
+}
diff --git a/src/ui/src/components/core/layout/CoreHorizontalStack.vue b/src/ui/src/components/core/layout/CoreHorizontalStack.vue
index 50959fad1..07573aed1 100644
--- a/src/ui/src/components/core/layout/CoreHorizontalStack.vue
+++ b/src/ui/src/components/core/layout/CoreHorizontalStack.vue
@@ -2,7 +2,7 @@
@@ -13,6 +13,7 @@