Skip to content

Commit 5b94fe5

Browse files
Merge pull request #207 from frappe/develop
2 parents 27c90d8 + a252085 commit 5b94fe5

File tree

7 files changed

+122
-29
lines changed

7 files changed

+122
-29
lines changed
Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11

2-
name: CI
2+
name: Server Tests
33

44
on:
55
push:
66
branches:
77
- master
8+
- develop
89
pull_request:
910

1011
jobs:
@@ -83,7 +84,7 @@ jobs:
8384
working-directory: /home/runner/frappe-bench
8485
run: |
8586
bench get-app builder $GITHUB_WORKSPACE
86-
bench setup requirements
87+
bench setup requirements --dev
8788
bench new-site --db-root-password root --admin-password admin test_site
8889
bench --site test_site install-app builder
8990
bench build
@@ -94,6 +95,31 @@ jobs:
9495
working-directory: /home/runner/frappe-bench
9596
run: |
9697
bench --site test_site set-config allow_tests true
97-
bench --site test_site run-tests --app builder
98+
bench --site test_site run-tests --app builder --coverage
9899
env:
99100
TYPE: server
101+
102+
- name: Upload coverage data
103+
uses: actions/upload-artifact@v3
104+
with:
105+
name: coverage-${{ matrix.container }}
106+
path: /home/runner/frappe-bench/sites/coverage.xml
107+
108+
coverage:
109+
name: Coverage Wrap Up
110+
needs: tests
111+
runs-on: ubuntu-latest
112+
steps:
113+
- name: Clone
114+
uses: actions/checkout@v3
115+
116+
- name: Download artifacts
117+
uses: actions/download-artifact@v3
118+
119+
- name: Upload coverage data
120+
uses: codecov/codecov-action@v3
121+
with:
122+
name: Server
123+
token: ${{ secrets.CODECOV_TOKEN }}
124+
fail_ci_if_error: true
125+
verbose: true

builder/builder/doctype/builder_page/builder_page.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,20 +88,26 @@ def before_insert(self):
8888
)
8989

9090
def on_update(self):
91-
if self.has_value_changed("dynamic_route") or self.has_value_changed("route"):
92-
get_web_pages_with_dynamic_routes.clear_cache()
93-
find_page_with_path.clear_cache()
91+
if (
92+
self.has_value_changed("dynamic_route")
93+
or self.has_value_changed("route")
94+
or self.has_value_changed("published")
95+
):
96+
self.clear_route_cache()
9497

9598
if self.has_value_changed("published") and not self.published:
96-
find_page_with_path.clear_cache()
97-
clear_cache(self.route)
9899
# if this is homepage then clear homepage from builder settings
99100
if frappe.get_cached_value("Builder Settings", None, "home_page") == self.route:
100101
frappe.db.set_value("Builder Settings", None, "home_page", None)
101102

102103
if frappe.conf.developer_mode and self.is_template:
103104
save_as_template(self)
104105

106+
def clear_route_cache(self):
107+
get_web_pages_with_dynamic_routes.clear_cache()
108+
find_page_with_path.clear_cache()
109+
clear_cache(self.route)
110+
105111
def on_trash(self):
106112
if self.is_template and frappe.conf.developer_mode:
107113
page_template_folder = os.path.join(
@@ -141,6 +147,11 @@ def publish(self, **kwargs):
141147

142148
return self.route
143149

150+
@frappe.whitelist()
151+
def unpublish(self, **kwargs):
152+
self.published = 0
153+
self.save()
154+
144155
def get_context(self, context):
145156
# delete default favicon
146157
del context.favicon
Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,64 @@
11
# Copyright (c) 2023, asdf and Contributors
22
# See license.txt
33

4-
# import frappe
4+
import frappe
5+
from frappe.desk.form.load import getdoc
56
from frappe.tests.utils import FrappeTestCase
7+
from frappe.website.serve import get_response_content
68

79

810
class TestBuilderPage(FrappeTestCase):
9-
pass
11+
@classmethod
12+
def setUpClass(cls):
13+
cls.page = frappe.get_doc(
14+
{
15+
"doctype": "Builder Page",
16+
"name": "test-page",
17+
"page_title": "Test Page",
18+
"published": 1,
19+
"route": "/test-page",
20+
"blocks": [{"element": "body", "children": [{"element": "h1", "innerHTML": "Hello World!"}]}],
21+
}
22+
).insert(ignore_if_duplicate=True)
23+
cls.page_with_dynamic_route = frappe.get_doc(
24+
{
25+
"doctype": "Builder Page",
26+
"page_title": "Test Page Dynamic Route",
27+
"published": 1,
28+
"route": "/test-page-dynamic-route/<name>",
29+
"dynamic_route": 1,
30+
"blocks": [
31+
{"element": "body", "children": [{"element": "h1", "innerHTML": "Dynamic Content!"}]}
32+
],
33+
}
34+
).insert(ignore_if_duplicate=True)
35+
36+
def test_can_render(self):
37+
content = get_response_content("/test-page")
38+
self.assertTrue("Hello World!" in content)
39+
40+
def test_onload(self):
41+
getdoc("Builder Page", self.page.name)
42+
self.assertEqual(frappe.response.docs[0].get("__onload").get("builder_path"), "builder")
43+
44+
def test_dynamic_route(self):
45+
from frappe.utils import get_html_for_route
46+
47+
content = get_html_for_route("/test-page-dynamic-route/123")
48+
self.assertTrue("Dynamic Content!" in content)
49+
50+
def test_publish_unpublish(self):
51+
self.page.unpublish()
52+
from frappe.utils import get_html_for_route
53+
54+
content = get_html_for_route("/test-page")
55+
self.assertTrue("The page you are looking for has gone missing" in content)
56+
57+
self.page.publish()
58+
content = get_response_content("/test-page")
59+
self.assertTrue("Hello World!" in content)
60+
61+
@classmethod
62+
def tearDownClass(cls):
63+
cls.page.delete()
64+
cls.page_with_dynamic_route.delete()

builder/www/_builder.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import frappe
2-
3-
no_cache = 1
42
from frappe.utils.telemetry import capture
53

64
from builder.hooks import builder_path
75

6+
no_cache = 1
7+
88

99
def get_context(context):
1010
csrf_token = frappe.sessions.get_csrf_token()

frontend/src/components/BuilderCanvas.vue

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -648,27 +648,27 @@ const toggleBlockSelection = (_block: Block) => {
648648
}
649649
};
650650
651-
const selectBlockRange = (_block: Block) => {
651+
const selectBlockRange = (newSelectedBlock: Block) => {
652652
const lastSelectedBlockId = selectedBlockIds.value[selectedBlockIds.value.length - 1];
653653
const lastSelectedBlock = findBlock(lastSelectedBlockId);
654-
if (!lastSelectedBlock) {
655-
_block.selectBlock();
654+
const lastSelectedBlockParent = lastSelectedBlock?.parentBlock;
655+
if (!lastSelectedBlock || !lastSelectedBlockParent) {
656+
newSelectedBlock.selectBlock();
656657
return;
657658
}
658659
const lastSelectedBlockIndex = lastSelectedBlock.parentBlock?.children.indexOf(lastSelectedBlock);
659-
const _blockIndex = _block.parentBlock?.children.indexOf(_block);
660-
if (lastSelectedBlockIndex === undefined || _blockIndex === undefined) {
660+
const newSelectedBlockIndex = newSelectedBlock.parentBlock?.children.indexOf(newSelectedBlock);
661+
const newSelectedBlockParent = newSelectedBlock.parentBlock;
662+
if (lastSelectedBlockIndex === undefined || newSelectedBlockIndex === undefined) {
661663
return;
662664
}
663-
const start = Math.min(lastSelectedBlockIndex, _blockIndex);
664-
const end = Math.max(lastSelectedBlockIndex, _blockIndex);
665-
const parentBlock = lastSelectedBlock.parentBlock;
666-
if (!parentBlock) {
667-
return;
665+
const start = Math.min(lastSelectedBlockIndex, newSelectedBlockIndex);
666+
const end = Math.max(lastSelectedBlockIndex, newSelectedBlockIndex);
667+
if (lastSelectedBlockParent === newSelectedBlockParent) {
668+
const blocks = lastSelectedBlockParent.children.slice(start, end + 1);
669+
selectedBlockIds.value = selectedBlockIds.value.concat(...blocks.map((b) => b.blockId));
670+
selectedBlockIds.value = Array.from(new Set(selectedBlockIds.value));
668671
}
669-
const blocks = parentBlock.children.slice(start, end + 1);
670-
selectedBlockIds.value = selectedBlockIds.value.concat(...blocks.map((b) => b.blockId));
671-
selectedBlockIds.value = Array.from(new Set(selectedBlockIds.value));
672672
};
673673
674674
const clearSelection = () => {

frontend/src/components/PageScript.vue

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@
3333
height="65vh"
3434
@save="savePageDataScript"
3535
:showSaveButton="true"
36-
description='Can be used to fetch dynamic data from server and pass it to the page.
37-
<br />
38-
eg. data.events = frappe.get_list("Event")'
36+
description='Use Data Script to provide dynamic data to your web page.<br>
37+
<b>Example:</b> data.events = frappe.get_list("Event")<br><br>
38+
For more details on how to write data script, refer to <b><a class="underline" href="https://docs.frappe.io/builder/data-script" target="_blank">this documentation</a></b>.
39+
'
3940
:show-line-numbers="true"></CodeEditor>
4041
</div>
4142
</template>

frontend/src/components/TextBlock.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
},
2828
}"
2929
v-if="editor"
30-
class="z-50 rounded-md border border-gray-300 bg-white p-1 text-lg">
30+
class="z-50 rounded-md border border-gray-300 bg-white p-1 text-lg shadow-2xl">
3131
<div v-if="settingLink" class="flex">
3232
<Input
3333
v-model="textLink"

0 commit comments

Comments
 (0)