From d1b80e5c6f57f7a3fbb43c1b8c57b09fc9942002 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 25 Oct 2024 12:40:19 +0530 Subject: [PATCH 001/118] fix(UX): Avoid outside click while selecting text closes: https://github.com/frappe/builder/issues/229 --- frontend/src/components/BuilderBlock.vue | 6 ++++++ frontend/src/components/TextBlock.vue | 10 ++++++++++ frontend/src/store.ts | 1 + 3 files changed, 17 insertions(+) diff --git a/frontend/src/components/BuilderBlock.vue b/frontend/src/components/BuilderBlock.vue index 719e36e5..e334ec74 100644 --- a/frontend/src/components/BuilderBlock.vue +++ b/frontend/src/components/BuilderBlock.vue @@ -231,6 +231,12 @@ const triggerContextMenu = (e: MouseEvent) => { const handleClick = (e: MouseEvent) => { if (isEditable.value) return; + if (store.preventClick) { + e.stopPropagation(); + e.preventDefault(); + store.preventClick = false; + return; + } selectBlock(e); e.stopPropagation(); e.preventDefault(); diff --git a/frontend/src/components/TextBlock.vue b/frontend/src/components/TextBlock.vue index 186f12c3..a2d19c74 100644 --- a/frontend/src/components/TextBlock.vue +++ b/frontend/src/components/TextBlock.vue @@ -111,6 +111,15 @@ ; const component = ref(null) as Ref; const overlayElement = document.querySelector("#overlay") as HTMLElement; let editor: Ref = ref(null); +let selectionTriggered = false as boolean; const props = defineProps({ block: { diff --git a/frontend/src/store.ts b/frontend/src/store.ts index 31f8d500..10a98b54 100644 --- a/frontend/src/store.ts +++ b/frontend/src/store.ts @@ -49,6 +49,7 @@ const useStore = defineStore("store", { autoSave: true, pageBlocks: [], propertyFilter: null, + preventClick: false, builderLayout: { rightPanelWidth: 275, leftPanelWidth: 250, From eed1d77e0b56125f00d19929704fb3de7ee4331c Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 25 Oct 2024 12:42:25 +0530 Subject: [PATCH 002/118] fix: Enter edit mode if the selected text block is clicked again ... instead of expecting double click --- frontend/src/components/BlockEditor.vue | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/components/BlockEditor.vue b/frontend/src/components/BlockEditor.vue index cb3699a9..e3445fa7 100644 --- a/frontend/src/components/BlockEditor.vue +++ b/frontend/src/components/BlockEditor.vue @@ -189,6 +189,11 @@ const handleClick = (ev: MouseEvent) => { preventCLick.value = false; return; } + + if (props.block.isText() || props.block.isButton() || props.block.isLink()) { + store.editableBlock = props.block; + } + const editorWrapper = editor.value; editorWrapper.classList.add("pointer-events-none"); let element = document.elementFromPoint(ev.x, ev.y) as HTMLElement; From 70e315413f75b925fe2a0aa98838c183b81adbb3 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 25 Oct 2024 12:44:03 +0530 Subject: [PATCH 003/118] fix(UX): Hide editor bordes to indicate that text block is in edit mode --- frontend/src/components/BuilderBlock.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/components/BuilderBlock.vue b/frontend/src/components/BuilderBlock.vue index e334ec74..3b8ccbaf 100644 --- a/frontend/src/components/BuilderBlock.vue +++ b/frontend/src/components/BuilderBlock.vue @@ -27,6 +27,7 @@ Date: Fri, 25 Oct 2024 12:51:57 +0530 Subject: [PATCH 004/118] fix: Remove padding and margin handlers on text blocks --- frontend/src/components/BlockEditor.vue | 62 +++++++++++++++---------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/frontend/src/components/BlockEditor.vue b/frontend/src/components/BlockEditor.vue index e3445fa7..5a59eacb 100644 --- a/frontend/src/components/BlockEditor.vue +++ b/frontend/src/components/BlockEditor.vue @@ -13,26 +13,14 @@ :class="getStyleClasses"> @@ -114,6 +93,41 @@ const guides = setGuides(props.target, canvasProps); const moving = ref(false); const preventCLick = ref(false); +const showPaddingHandler = computed(() => { + return ( + isBlockSelected.value && + !resizing.value && + !props.editable && + !blockController.multipleBlocksSelected() && + !props.block.isSVG() && + !props.block.isText() + ); +}); + +const showMarginHandler = computed(() => { + return ( + isBlockSelected.value && + !props.block.isRoot() && + !resizing.value && + !props.editable && + !blockController.multipleBlocksSelected() && + !props.block.isText() + ); +}); + +const showBorderRadiusHandler = computed(() => { + return ( + isBlockSelected && + !props.block.isRoot() && + !props.block.isText() && + !props.block.isHTML() && + !props.block.isSVG() && + !props.editable && + !resizing && + !blockController.multipleBlocksSelected() + ); +}); + watchEffect(() => { props.block.getStyle("top"); props.block.getStyle("left"); From 231be769fde3b80698566c98ec58a59b92a76cd4 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Fri, 25 Oct 2024 14:22:48 +0530 Subject: [PATCH 005/118] Refactor: Simplify block properties message --- frontend/src/components/BlockProperties.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/components/BlockProperties.vue b/frontend/src/components/BlockProperties.vue index dce8b7de..b3347582 100644 --- a/frontend/src/components/BlockProperties.vue +++ b/frontend/src/components/BlockProperties.vue @@ -28,9 +28,7 @@
-

- Select a block to edit properties. -

+

Select a block to edit properties

From 6074819c239a2f2aae159616e15ed2f8981ff3b2 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 11 Dec 2024 12:58:43 +0530 Subject: [PATCH 053/118] chore: Update README - Simplify setup guide - Remove unnecessary text - Add frontend development setup guide --- README.md | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 11f9c388..fb2266ca 100644 --- a/README.md +++ b/README.md @@ -32,8 +32,7 @@ Most existing solutions were either too complex, too restrictive, or difficult t - **Responsive Views:** Ensure your sites look great on any device without the fuss. - **Frappe CMS Integration:** Easily fetch data from your database and create dynamic pages. - **Scripting Capabilities:** Customize with client scripts, global scripts, and styles. -- **Efficient Workflow:** Use subtle shortcuts like image dropping and streamlined page copying and more to efficiently develop pages. -- **One-Click Publishing:** Instantly share your creations with the world in a single click. +- **One-Click Publishing:** Instantly share your creation with the world in a single click. - **Performance Excellence:** Frappe Builder does not bloat web pages with unnecessary scripts hence pages built with Frappe Builder are highly performant, consistently scoring high on Google Lighthouse tests. ## Getting Started (Production) @@ -81,9 +80,21 @@ The script will set up a production-ready instance of Frappe Builder with all th ## Getting Started (Development) -### Codespaces +### Local Setup + +1. [Setup Bench](https://docs.frappe.io/framework/user/en/installation). +1. In the frappe-bench directory, run `bench start` and keep it running. +1. Open a new terminal session and cd into `frappe-bench` directory and run following commands: + ```sh + $ bench get-app builder + $ bench new-site sitename.localhost --install-app builder + $ bench browse sitename.localhost --user Administrator + ``` +1. Access the builder page at `sitename.localhost:8000/builder` in your web browser. -https://github.com/frappe/builder/assets/13928957/c96ce2ce-9eb3-4bd5-8e92-0b39d971cb00 +### Github Codespaces + + 1. Open [this link](https://github.com/codespaces/new?hide_repo_select=true&ref=master&repo=587413812&skip_quickstart=true&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&geo=SoutheastAsia) and click on "Create Codespace". 2. Wait for initialization (~15 mins). @@ -92,22 +103,15 @@ https://github.com/frappe/builder/assets/13928957/c96ce2ce-9eb3-4bd5-8e92-0b39d9 5. Log in with "Administrator" as the username and "admin" as the password. 6. Go to `.github.dev/builder` to access the builder interface. -### Local Setup - -1. [Install Bench](https://github.com/frappe/bench). -2. Install Frappe Builder app: - ```sh - $ bench get-app builder - ``` -3. Create a site with the builder app: - ```sh - $ bench --site sitename.localhost install-app builder +**For Frontend Developement** +1. Open a new terminal session and cd into `frappe-bench/apps/builder`, and run the following commands: ``` -4. Open the site in the browser: - ```sh - $ bench browse sitename.localhost --user Administrator + yarn install + yarn dev ``` -5. Access the builder page at `sitename.localhost:8000/builder` in your web browser. +1. Now, you can access the site on vite dev server at `http://sitename.localhost:8080` + +**Note:** You'll find all the code related to Builder's frontend inside `frappe-bench/apps/builder/frontend`

From bc5ad4a563c0d6a9f82b32ae70cc22db0833911d Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:07:55 +0530 Subject: [PATCH 054/118] chore: Update README Add "Under the hood" and figma link --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fb2266ca..30329d84 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ The script will set up a production-ready instance of Frappe Builder with all th 5. Log in with "Administrator" as the username and "admin" as the password. 6. Go to `.github.dev/builder` to access the builder interface. -**For Frontend Developement** +**For Frontend Development** 1. Open a new terminal session and cd into `frappe-bench/apps/builder`, and run the following commands: ``` yarn install @@ -113,13 +113,18 @@ The script will set up a production-ready instance of Frappe Builder with all th **Note:** You'll find all the code related to Builder's frontend inside `frappe-bench/apps/builder/frontend` -

+### Under the hood -### Need help? +- [Frappe Framework](https://github.com/frappe/frappe): A full-stack web application framework written in Python and Javascript. The framework provides a robust foundation for building web applications, including a database abstraction layer, user authentication, and a REST API. +- [Frappe UI](https://github.com/frappe/frappe-ui): A Vue-based UI library, to provide a modern user interface. The Frappe UI library provides a variety of components that can be used to build single-page applications on top of the Frappe Framework. + + +### Links - [Telegram Public Group](https://t.me/frappebuilder) - [Discuss Forum](https://discuss.frappe.io/c/frappe-builder/83) - [Documentation](https://docs.frappe.io/builder) +- [Figma Plugin (Beta)](https://www.figma.com/community/plugin/1417835732014419099/figma-to-frappe-builder)

From 11a1c40b2fc2868be93422b1a96afe3d31e19715 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 11 Dec 2024 13:44:03 +0530 Subject: [PATCH 055/118] chore: Remove codespaces setup guide - To avoid confusion --- README.md | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 30329d84..1df3f23f 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,13 @@ Most existing solutions were either too complex, too restrictive, or difficult t - **One-Click Publishing:** Instantly share your creation with the world in a single click. - **Performance Excellence:** Frappe Builder does not bloat web pages with unnecessary scripts hence pages built with Frappe Builder are highly performant, consistently scoring high on Google Lighthouse tests. +### Under the hood + +- [Frappe Framework](https://github.com/frappe/frappe): A full-stack web application framework. +- [Frappe UI](https://github.com/frappe/frappe-ui): A Vue-based UI library, to provide a modern user interface. + + + ## Getting Started (Production) ### Managed Hosting @@ -92,17 +99,6 @@ The script will set up a production-ready instance of Frappe Builder with all th ``` 1. Access the builder page at `sitename.localhost:8000/builder` in your web browser. -### Github Codespaces - - - -1. Open [this link](https://github.com/codespaces/new?hide_repo_select=true&ref=master&repo=587413812&skip_quickstart=true&machine=standardLinux32gb&devcontainer_path=.devcontainer%2Fdevcontainer.json&geo=SoutheastAsia) and click on "Create Codespace". -2. Wait for initialization (~15 mins). -3. Run `bench start` from the terminal tab. -4. Click on the link beside "8000" port under "Ports" tab. -5. Log in with "Administrator" as the username and "admin" as the password. -6. Go to `.github.dev/builder` to access the builder interface. - **For Frontend Development** 1. Open a new terminal session and cd into `frappe-bench/apps/builder`, and run the following commands: ``` @@ -113,11 +109,7 @@ The script will set up a production-ready instance of Frappe Builder with all th **Note:** You'll find all the code related to Builder's frontend inside `frappe-bench/apps/builder/frontend` -### Under the hood - -- [Frappe Framework](https://github.com/frappe/frappe): A full-stack web application framework written in Python and Javascript. The framework provides a robust foundation for building web applications, including a database abstraction layer, user authentication, and a REST API. -- [Frappe UI](https://github.com/frappe/frappe-ui): A Vue-based UI library, to provide a modern user interface. The Frappe UI library provides a variety of components that can be used to build single-page applications on top of the Frappe Framework. - +

### Links @@ -126,9 +118,7 @@ The script will set up a production-ready instance of Frappe Builder with all th - [Documentation](https://docs.frappe.io/builder) - [Figma Plugin (Beta)](https://www.figma.com/community/plugin/1417835732014419099/figma-to-frappe-builder) -

-
From eeb5931fce85551a5e4666383fadec2730c1a550 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 11 Dec 2024 14:54:28 +0530 Subject: [PATCH 056/118] chore: Fix heading case consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Also add emojis for key features 💅 --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1df3f23f..17efb1fd 100644 --- a/README.md +++ b/README.md @@ -28,14 +28,14 @@ Most existing solutions were either too complex, too restrictive, or difficult t ### Key Features -- **Intuitive Visual Builder:** Simplify your workflow with a Figma-like editor. -- **Responsive Views:** Ensure your sites look great on any device without the fuss. -- **Frappe CMS Integration:** Easily fetch data from your database and create dynamic pages. -- **Scripting Capabilities:** Customize with client scripts, global scripts, and styles. -- **One-Click Publishing:** Instantly share your creation with the world in a single click. -- **Performance Excellence:** Frappe Builder does not bloat web pages with unnecessary scripts hence pages built with Frappe Builder are highly performant, consistently scoring high on Google Lighthouse tests. - -### Under the hood +- ✨ **Intuitive Visual Builder:** Simplify your workflow with a Figma-like editor. +- 📱 **Responsive Views:** Ensure your sites look great on any device without the fuss. +- 🛠️ **Frappe CMS Integration:** Easily fetch data from your database and create dynamic pages. +- 🧑‍💻 **Scripting Capabilities:** Customize with client scripts, global scripts, and styles. +- 🚀 **One-Click Publishing:** Instantly share your creation with the world in a single click. +- ⚡ **Performance Excellence:** Frappe Builder does not bloat web pages with unnecessary scripts hence pages built with Frappe Builder are highly performant, consistently scoring high on Google Lighthouse tests. + +### Under the Hood - [Frappe Framework](https://github.com/frappe/frappe): A full-stack web application framework. - [Frappe UI](https://github.com/frappe/frappe-ui): A Vue-based UI library, to provide a modern user interface. From ce96b4303da2bb8f452082eae56498e89ffdabe9 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 11 Dec 2024 15:34:35 +0530 Subject: [PATCH 057/118] chore: Update README - Update screenshot - Remove unnecessary badges - Fix footer spacing --- README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 17efb1fd..ed31f3ba 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,23 @@ Frappe Builder Logo +

Frappe Builder

-**Crafting Web Pages Made Effortless!** +**Crafting Web Pages Made Effortless** -![GitHub license](https://img.shields.io/github/license/frappe/builder) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/frappe/builder) [![codecov](https://codecov.io/github/frappe/builder/branch/develop/graph/badge.svg)](https://codecov.io/github/frappe/builder) [![unittests](https://github.com/frappe/builder/actions/workflows/server-tests.yml/badge.svg)](https://github.com/frappe/builder/actions/workflows/server-tests.yml) -![Frappe Builder](https://github.com/user-attachments/assets/e906545e-101e-4d55-8a25-2c4f6380ea5e) +
+ + + Frappe Builder Screenshot + +
+ [Website](https://frappe.io/builder) - [Documentation](https://docs.frappe.io/builder)
@@ -118,7 +124,8 @@ The script will set up a production-ready instance of Frappe Builder with all th - [Documentation](https://docs.frappe.io/builder) - [Figma Plugin (Beta)](https://www.figma.com/community/plugin/1417835732014419099/figma-to-frappe-builder) -
+

+
From 66f41c2ab59fed61ef4b59eec0593c3aca38759c Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 11 Dec 2024 21:12:59 +0530 Subject: [PATCH 059/118] fix: Handle history pausing and resuming properly - Avoid duplicate snapshot - Properly pause history handler while choosing color --- frontend/src/components/BlockLayers.vue | 12 +- frontend/src/components/BoxResizer.vue | 4 +- frontend/src/components/BuilderCanvas.vue | 6 +- .../src/components/Controls/ColorPicker.vue | 6 +- frontend/src/components/TextBlock.vue | 6 +- frontend/src/pages/PageBuilder.vue | 4 +- frontend/src/store.ts | 3 - frontend/src/utils/block.ts | 4 +- frontend/src/utils/helpers.ts | 5 + frontend/src/utils/useCanvasHistory.ts | 144 +++++++++++++----- frontend/src/utils/useDraggableBlock.ts | 4 +- 11 files changed, 136 insertions(+), 62 deletions(-) diff --git a/frontend/src/components/BlockLayers.vue b/frontend/src/components/BlockLayers.vue index 0752f04f..e2a4f63a 100644 --- a/frontend/src/components/BlockLayers.vue +++ b/frontend/src/components/BlockLayers.vue @@ -15,11 +15,7 @@ :title="element.blockId" @contextmenu.prevent.stop="onContextMenu" class="min-w-24 cursor-pointer overflow-hidden rounded border border-transparent bg-surface-white bg-opacity-50 text-base text-ink-gray-7" - @click.stop=" - store.activeCanvas?.history.pause(); - store.selectBlock(element, $event, false, true); - store.activeCanvas?.history.resume(); - " + @click.stop="selectBlock(element, $event)" @mouseover.stop="store.hoveredBlock = element.blockId" @mouseleave.stop="store.hoveredBlock = null"> { return false; }; +const selectBlock = (block: Block, event: MouseEvent) => { + const pauseId = store.activeCanvas?.history?.pause(); + store.selectBlock(block, event, false, true); + pauseId && store.activeCanvas?.history?.resume(pauseId); +}; + defineExpose({ toggleExpanded, isExpandedInTree, diff --git a/frontend/src/components/BoxResizer.vue b/frontend/src/components/BoxResizer.vue index 53a25e99..26913e67 100644 --- a/frontend/src/components/BoxResizer.vue +++ b/frontend/src/components/BoxResizer.vue @@ -60,10 +60,10 @@ onMounted(() => { watch(resizing, () => { if (resizing.value) { - store.activeCanvas?.history.pause(); + store.activeCanvas?.history?.pause(); emit("resizing", true); } else { - store.activeCanvas?.history.resume(true); + store.activeCanvas?.history?.resume(undefined, true, true); emit("resizing", false); } }); diff --git a/frontend/src/components/BuilderCanvas.vue b/frontend/src/components/BuilderCanvas.vue index 3aacafa9..6ffa34ee 100644 --- a/frontend/src/components/BuilderCanvas.vue +++ b/frontend/src/components/BuilderCanvas.vue @@ -290,7 +290,7 @@ function setEvents() { if (store.mode === "select") { return; } else { - canvasHistory.value?.pause(); + const pauseId = canvasHistory.value?.pause(); ev.stopPropagation(); let element = document.elementFromPoint(ev.x, ev.y) as HTMLElement; let block = getFirstBlock(); @@ -358,7 +358,7 @@ function setEvents() { store.mode = "select"; }, 50); if (store.mode === "text") { - canvasHistory.value?.resume(true); + pauseId && canvasHistory.value?.resume(pauseId, true); store.editableBlock = childBlock; return; } @@ -373,7 +373,7 @@ function setEvents() { childBlock.setBaseStyle("height", "200px"); } } - canvasHistory.value?.resume(true); + pauseId && canvasHistory.value?.resume(pauseId, true); }, { once: true }, ); diff --git a/frontend/src/components/Controls/ColorPicker.vue b/frontend/src/components/Controls/ColorPicker.vue index 9f935713..714b0025 100644 --- a/frontend/src/components/Controls/ColorPicker.vue +++ b/frontend/src/components/Controls/ColorPicker.vue @@ -155,6 +155,7 @@ const setHueSelectorPosition = (color: HashString) => { const handleSelectorMove = (ev: MouseEvent) => { setColor(ev); + const pauseId = store.activeCanvas?.history?.pause(); const mouseMove = (mouseMoveEvent: MouseEvent) => { mouseMoveEvent.preventDefault(); setColor(mouseMoveEvent); @@ -165,6 +166,7 @@ const handleSelectorMove = (ev: MouseEvent) => { (mouseUpEvent) => { document.removeEventListener("mousemove", mouseMove); mouseUpEvent.preventDefault(); + pauseId && store.activeCanvas?.history?.resume(pauseId, true); }, { once: true }, ); @@ -172,7 +174,7 @@ const handleSelectorMove = (ev: MouseEvent) => { const handleHueSelectorMove = (ev: MouseEvent) => { setHue(ev); - store.activeCanvas?.history.pause(); + const pauseId = store.activeCanvas?.history?.pause(); const mouseMove = (mouseMoveEvent: MouseEvent) => { mouseMoveEvent.preventDefault(); setHue(mouseMoveEvent); @@ -183,7 +185,7 @@ const handleHueSelectorMove = (ev: MouseEvent) => { (mouseUpEvent) => { document.removeEventListener("mousemove", mouseMove); mouseUpEvent.preventDefault(); - store.activeCanvas?.history.resume(true); + pauseId && store.activeCanvas?.history?.resume(pauseId, true); }, { once: true }, ); diff --git a/frontend/src/components/TextBlock.vue b/frontend/src/components/TextBlock.vue index ec9198b3..1cea8c8c 100644 --- a/frontend/src/components/TextBlock.vue +++ b/frontend/src/components/TextBlock.vue @@ -32,7 +32,7 @@ { // TODO: Refactor with useMagicKeys useEventListener(document, "keydown", (e) => { if (isTargetEditable(e)) return; - if (e.key === "z" && isCtrlOrCmd(e) && !e.shiftKey && store.activeCanvas?.history.canUndo) { + if (e.key === "z" && isCtrlOrCmd(e) && !e.shiftKey && store.activeCanvas?.history?.canUndo) { store.activeCanvas?.history.undo(); e.preventDefault(); return; } - if (e.key === "z" && e.shiftKey && isCtrlOrCmd(e) && store.activeCanvas?.history.canRedo) { + if (e.key === "z" && e.shiftKey && isCtrlOrCmd(e) && store.activeCanvas?.history?.canRedo) { store.activeCanvas?.history.redo(); e.preventDefault(); return; diff --git a/frontend/src/store.ts b/frontend/src/store.ts index f71e7675..d71aefe6 100644 --- a/frontend/src/store.ts +++ b/frontend/src/store.ts @@ -214,7 +214,6 @@ const useStore = defineStore("store", { scrollLayerIntoView: boolean | ScrollLogicalPosition = true, scrollBlockIntoView = false, ) { - this.activeCanvas?.history?.pause(); if (this.settingPage) { return; } @@ -234,8 +233,6 @@ const useStore = defineStore("store", { ?.scrollIntoView({ behavior: "instant", block: align, inline: "center" }); }); } - - this.activeCanvas?.history?.resume(); this.editableBlock = null; if (scrollBlockIntoView) { this.activeCanvas?.scrollBlockIntoView(block); diff --git a/frontend/src/utils/block.ts b/frontend/src/utils/block.ts index f76c5d50..05bdb140 100644 --- a/frontend/src/utils/block.ts +++ b/frontend/src/utils/block.ts @@ -734,7 +734,7 @@ class Block implements BlockOptions { return; } const store = useStore(); - store.activeCanvas?.history.pause(); + const pauseId = store.activeCanvas?.history?.pause(); const blockCopy = getBlockCopy(this); const parentBlock = this.getParentBlock(); @@ -756,8 +756,8 @@ class Block implements BlockOptions { if (child) { child.selectBlock(); } - store.activeCanvas?.history.resume(true); }); + pauseId && store.activeCanvas?.history?.resume(pauseId, true); } getPadding() { const padding = this.getStyle("padding") || "0px"; diff --git a/frontend/src/utils/helpers.ts b/frontend/src/utils/helpers.ts index 7aec1545..810b3e55 100644 --- a/frontend/src/utils/helpers.ts +++ b/frontend/src/utils/helpers.ts @@ -423,6 +423,10 @@ async function getFontName(file_url: string) { return opentype.parse(await getFontArrayBuffer(file_url)).names.fullName.en; } +function generateId() { + return Math.random().toString(36).substr(2, 9); +} + export { addPxToNumber, alert, @@ -431,6 +435,7 @@ export { dataURLtoFile, detachBlockFromComponent, findNearestSiblingIndex, + generateId, getBlockCopy, getBlockInstance, getBlockObjectCopy as getBlockObject, diff --git a/frontend/src/utils/useCanvasHistory.ts b/frontend/src/utils/useCanvasHistory.ts index e2a94f31..feb62370 100644 --- a/frontend/src/utils/useCanvasHistory.ts +++ b/frontend/src/utils/useCanvasHistory.ts @@ -1,52 +1,82 @@ import Block from "@/utils/block"; -import { getBlockInstance, getBlockObject } from "@/utils/helpers"; +import { generateId, getBlockInstance, getBlockString } from "@/utils/helpers"; import { debounceFilter, pausableFilter, watchIgnorable } from "@vueuse/core"; import { nextTick, ref, Ref } from "vue"; type CanvasState = { - block: Block; + block: string; selectedBlockIds: string[]; }; -const CAPACITY = 50; + +type PauseId = string & { __brand: "PauseId" }; + +const CAPACITY = 200; const DEBOUNCE_DELAY = 200; export function useCanvasHistory(source: Ref, selectedBlockIds: Ref) { + const undoStack = ref([]) as Ref; + const redoStack = ref([]) as Ref; + const last = ref(createHistoryRecord(source, selectedBlockIds)); + const pauseIdSet = new Set(); + const { - eventFilter: composedFilter, - pause, - resume: resumeTracking, + eventFilter: blockWatcherFilter, + pause: pauseBlockWatcher, + resume: resumeBlockWatcher, isActive: isTracking, } = pausableFilter(debounceFilter(DEBOUNCE_DELAY)); - const { ignoreUpdates, ignorePrevAsyncUpdates, stop } = watchIgnorable(source, commit, { + const { + eventFilter: selectionWatherFilter, + pause: pauseSelectionWatcher, + resume: resumeSelectionWatcher, + } = pausableFilter(); + + function commit() { + // console.log("committing..."); + undoStack.value.unshift(last.value); + last.value = createHistoryRecord(source, selectedBlockIds); + if (undoStack.value.length > CAPACITY) { + undoStack.value.splice(CAPACITY, Number.POSITIVE_INFINITY); + } + if (redoStack.value.length) { + redoStack.value.splice(0, redoStack.value.length); + } + } + + // const debouncedCommit = useDebounceFn(commit, DEBOUNCE_DELAY); + + const { + ignoreUpdates: ignoreBlockUpdates, + ignorePrevAsyncUpdates: ignorePrevAsyncBlockUpdates, + stop: stopBlockWatcher, + } = watchIgnorable(source, commit, { + deep: true, + flush: "post", + eventFilter: blockWatcherFilter, + }); + + const { + ignoreUpdates: ignoreSelectedBlockUpdates, + ignorePrevAsyncUpdates: ignorePrevSelectedBlockUpdates, + stop: stopSelectedBlockUpdates, + } = watchIgnorable(selectedBlockIds, updateSelections, { deep: true, flush: "post", - eventFilter: composedFilter, + eventFilter: selectionWatherFilter, }); - function setSource(value: string) { - const obj = JSON.parse(value) as CanvasState; - ignorePrevAsyncUpdates(); - ignoreUpdates(() => { - source.value = getBlockInstance(obj.block); - selectedBlockIds.value = obj.selectedBlockIds; + function setSource(value: CanvasState) { + ignorePrevAsyncBlockUpdates(); + ignoreBlockUpdates(() => { + source.value = getBlockInstance(value.block); }); - } - const last = ref(createHistoryRecord(source, selectedBlockIds)); - function commit() { - nextTick(() => { - undoStack.value.unshift(last.value); - last.value = createHistoryRecord(source, selectedBlockIds); - if (undoStack.value.length > CAPACITY) { - undoStack.value.splice(CAPACITY, Number.POSITIVE_INFINITY); - } - if (redoStack.value.length) { - redoStack.value.splice(0, redoStack.value.length); - } + ignorePrevSelectedBlockUpdates(); + ignoreSelectedBlockUpdates(() => { + selectedBlockIds.value = [...value.selectedBlockIds]; }); + last.value = value; } - const undoStack = ref([]) as Ref; - const redoStack = ref([]) as Ref; function undo() { const state = undoStack.value.shift(); @@ -74,11 +104,6 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref 0; } @@ -87,23 +112,66 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref 0; } + function updateSelections() { + nextTick(() => { + last.value.selectedBlockIds = [...selectedBlockIds.value]; + }); + } + + function pause() { + pauseBlockWatcher(); + pauseSelectionWatcher(); + const pauseId = generateId() as PauseId; + pauseIdSet.add(pauseId); + // console.log("\npausing...", pauseId); + return pauseId as PauseId; + } + + function resume(pauseId?: PauseId, commitNow?: boolean, force?: boolean) { + nextTick(() => { + // console.log("resuming...", pauseId); + if (pauseId && pauseIdSet.has(pauseId)) { + pauseIdSet.delete(pauseId); + } else if (!force) { + return; + } + + if (pauseIdSet.size && !force) { + return; + } + resumeTracking(); + if (commitNow) commit(); + }); + } + + function resumeTracking() { + resumeBlockWatcher(); + resumeSelectionWatcher(); + } + + function stop() { + stopBlockWatcher(); + stopSelectedBlockUpdates(); + } + return { undo, redo, dispose, pause, - resumeTracking, resume, - isTracking, canUndo, canRedo, + isTracking, batch: () => {}, + undoStack, + redoStack, }; } function createHistoryRecord(source: Ref, selectedBlockIds: Ref) { - return JSON.stringify({ - block: getBlockObject(source.value), + return { + block: getBlockString(source.value), selectedBlockIds: selectedBlockIds.value, - }); + }; } diff --git a/frontend/src/utils/useDraggableBlock.ts b/frontend/src/utils/useDraggableBlock.ts index 33492631..08dcc926 100644 --- a/frontend/src/utils/useDraggableBlock.ts +++ b/frontend/src/utils/useDraggableBlock.ts @@ -34,7 +34,7 @@ export function useDraggableBlock(block: Block, target: HTMLElement, options: { }; const handleDrop = (e: DragEvent) => { - store.activeCanvas?.history.pause(); + const pauseId = store.activeCanvas?.history?.pause(); // move block to new container if (e.dataTransfer) { const draggingBlockId = e.dataTransfer.getData("draggingBlockId"); @@ -55,7 +55,7 @@ export function useDraggableBlock(block: Block, target: HTMLElement, options: { e.stopPropagation(); } } - store.activeCanvas?.history.resume(true); + pauseId && store.activeCanvas?.history?.resume(pauseId, true); }; const handleDragEnd = (e: DragEvent) => { From ea3de6b0f5a54e859fa9fa9382d9001fb8cf2a29 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 11 Dec 2024 21:13:11 +0530 Subject: [PATCH 060/118] refactor: Organize code and add batch function --- frontend/src/utils/useCanvasHistory.ts | 101 +++++++++++++------------ 1 file changed, 51 insertions(+), 50 deletions(-) diff --git a/frontend/src/utils/useCanvasHistory.ts b/frontend/src/utils/useCanvasHistory.ts index feb62370..d64d80e6 100644 --- a/frontend/src/utils/useCanvasHistory.ts +++ b/frontend/src/utils/useCanvasHistory.ts @@ -7,16 +7,15 @@ type CanvasState = { block: string; selectedBlockIds: string[]; }; - type PauseId = string & { __brand: "PauseId" }; const CAPACITY = 200; -const DEBOUNCE_DELAY = 200; +const DEBOUNCE_DELAY = 100; export function useCanvasHistory(source: Ref, selectedBlockIds: Ref) { const undoStack = ref([]) as Ref; const redoStack = ref([]) as Ref; - const last = ref(createHistoryRecord(source, selectedBlockIds)); + const last = ref(createHistoryRecord()); const pauseIdSet = new Set(); const { @@ -32,20 +31,6 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref CAPACITY) { - undoStack.value.splice(CAPACITY, Number.POSITIVE_INFINITY); - } - if (redoStack.value.length) { - redoStack.value.splice(0, redoStack.value.length); - } - } - - // const debouncedCommit = useDebounceFn(commit, DEBOUNCE_DELAY); - const { ignoreUpdates: ignoreBlockUpdates, ignorePrevAsyncUpdates: ignorePrevAsyncBlockUpdates, @@ -66,6 +51,30 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref CAPACITY) { + undoStack.value.splice(CAPACITY, Number.POSITIVE_INFINITY); + } + if (redoStack.value.length) { + redoStack.value.splice(0, redoStack.value.length); + } + } + + function updateSelections() { + nextTick(() => { + last.value.selectedBlockIds = [...selectedBlockIds.value]; + }); + } + + function createHistoryRecord() { + return { + block: getBlockString(source.value), + selectedBlockIds: selectedBlockIds.value, + }; + } + function setSource(value: CanvasState) { ignorePrevAsyncBlockUpdates(); ignoreBlockUpdates(() => { @@ -86,6 +95,10 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref 0; + } + function redo() { const state = redoStack.value.shift(); if (state) { @@ -94,6 +107,15 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref 0; + } + + function stop() { + stopBlockWatcher(); + stopSelectedBlockUpdates(); + } + const clear = () => { undoStack.value.splice(0, undoStack.value.length); redoStack.value.splice(0, redoStack.value.length); @@ -104,29 +126,19 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref 0; - } - - function canRedo() { - return redoStack.value.length > 0; - } - - function updateSelections() { - nextTick(() => { - last.value.selectedBlockIds = [...selectedBlockIds.value]; - }); - } - function pause() { pauseBlockWatcher(); pauseSelectionWatcher(); const pauseId = generateId() as PauseId; pauseIdSet.add(pauseId); - // console.log("\npausing...", pauseId); return pauseId as PauseId; } + function resumeTracking() { + resumeBlockWatcher(); + resumeSelectionWatcher(); + } + function resume(pauseId?: PauseId, commitNow?: boolean, force?: boolean) { nextTick(() => { // console.log("resuming...", pauseId); @@ -144,34 +156,23 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref void) { + const pauseId = pause(); + callback(); + resume(pauseId, true); } return { undo, redo, - dispose, pause, resume, + batch, canUndo, canRedo, - isTracking, - batch: () => {}, + dispose, undoStack, redoStack, - }; -} - -function createHistoryRecord(source: Ref, selectedBlockIds: Ref) { - return { - block: getBlockString(source.value), - selectedBlockIds: selectedBlockIds.value, + isTracking, }; } From 031ca00ca9ef154b81cf3cc3ec3227ecb1ab87d2 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Thu, 12 Dec 2024 16:43:02 +0530 Subject: [PATCH 061/118] chore: Update README.md - Use optimized images for faster load - Make logo smaller --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 700676c8..a5d7b4a7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@
- Frappe Builder Logo + Frappe Builder Logo From 602e46db4ac46258e02a29f81b8d3a07fe6dea83 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Fri, 13 Dec 2024 10:07:20 +0530 Subject: [PATCH 062/118] chore: Update README.md - Use optimized screenshots --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a5d7b4a7..d67a330a 100644 --- a/README.md +++ b/README.md @@ -16,12 +16,11 @@
- - Frappe Builder Screenshot + + Frappe Builder Screenshot
- [Website](https://frappe.io/builder) - [Documentation](https://docs.frappe.io/builder)
From 3c4227a4025d60a54f3e2dbdb9697cdd50dd8eb8 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sun, 15 Dec 2024 17:59:39 +0530 Subject: [PATCH 063/118] fix: Only show radiusHandler if block is selected --- frontend/src/components/BlockEditor.vue | 2 +- frontend/src/components/PaddingHandler.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/BlockEditor.vue b/frontend/src/components/BlockEditor.vue index 2c2aa214..a123b182 100644 --- a/frontend/src/components/BlockEditor.vue +++ b/frontend/src/components/BlockEditor.vue @@ -117,7 +117,7 @@ const showMarginHandler = computed(() => { const showBorderRadiusHandler = computed(() => { return ( - isBlockSelected && + isBlockSelected.value && !props.block.isRoot() && !props.block.isText() && !props.block.isHTML() && diff --git a/frontend/src/components/PaddingHandler.vue b/frontend/src/components/PaddingHandler.vue index 2237117d..2c50991d 100644 --- a/frontend/src/components/PaddingHandler.vue +++ b/frontend/src/components/PaddingHandler.vue @@ -308,7 +308,7 @@ const handlePadding = (ev: MouseEvent, position: Position) => { updating.value = false; mouseUpEvent.preventDefault(); }, - { once: true } + { once: true }, ); }; From 4c1e4392ace2bc641093165850c41e031fefa15f Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Sun, 15 Dec 2024 22:42:00 +0530 Subject: [PATCH 064/118] refactor: Make BuilderCanvas lighter and improve readability - Move all canvas events to useCanvasEvents - DropZone funtionality to useCanvasrDropZone - All utilities to useCanvasrUtils --- frontend/src/components/BuilderBlock.vue | 2 +- frontend/src/components/BuilderCanvas.vue | 697 ++----------------- frontend/src/components/BuilderLeftPanel.vue | 4 +- frontend/src/store.ts | 13 +- frontend/src/types/Builder/BuilderCanvas.ts | 24 + frontend/src/utils/block.ts | 2 +- frontend/src/utils/useBlockSelection.ts | 86 +++ frontend/src/utils/useCanvasDropZone.ts | 119 ++++ frontend/src/utils/useCanvasEvents.ts | 210 ++++++ frontend/src/utils/useCanvasUtils.ts | 286 ++++++++ 10 files changed, 806 insertions(+), 637 deletions(-) create mode 100644 frontend/src/types/Builder/BuilderCanvas.ts create mode 100644 frontend/src/utils/useBlockSelection.ts create mode 100644 frontend/src/utils/useCanvasDropZone.ts create mode 100644 frontend/src/utils/useCanvasEvents.ts create mode 100644 frontend/src/utils/useCanvasUtils.ts diff --git a/frontend/src/components/BuilderBlock.vue b/frontend/src/components/BuilderBlock.vue index 3b8ccbaf..683bf01f 100644 --- a/frontend/src/components/BuilderBlock.vue +++ b/frontend/src/components/BuilderBlock.vue @@ -4,7 +4,7 @@ :selected="isSelected" @click="handleClick" @dblclick="handleDoubleClick" - @contextmenu="triggerContextMenu($event)" + @contextmenu="triggerContextMenu" @mouseover="handleMouseOver" @mouseleave="handleMouseLeave" :data-block-id="block.blockId" diff --git a/frontend/src/components/BuilderCanvas.vue b/frontend/src/components/BuilderCanvas.vue index 6ffa34ee..9f215f4c 100644 --- a/frontend/src/components/BuilderCanvas.vue +++ b/frontend/src/components/BuilderCanvas.vue @@ -76,22 +76,15 @@ diff --git a/frontend/src/components/BuilderCanvas.vue b/frontend/src/components/BuilderCanvas.vue index 9f215f4c..8f570aea 100644 --- a/frontend/src/components/BuilderCanvas.vue +++ b/frontend/src/components/BuilderCanvas.vue @@ -78,11 +78,12 @@ import LoadingIcon from "@/components/Icons/Loading.vue"; import { BreakpointConfig, CanvasHistory } from "@/types/Builder/BuilderCanvas"; import Block from "@/utils/block"; -import { useCanvasUtils } from "@/utils/useCanvasUtils"; import { getBlockCopy } from "@/utils/helpers"; -import { useCanvasEvents } from "@/utils/useCanvasEvents"; +import { useBlockEventHandlers } from "@/utils/useBlockEventHandlers"; import { useBlockSelection } from "@/utils/useBlockSelection"; import { useCanvasDropZone } from "@/utils/useCanvasDropZone"; +import { useCanvasEvents } from "@/utils/useCanvasEvents"; +import { useCanvasUtils } from "@/utils/useCanvasUtils"; import { FeatherIcon } from "frappe-ui"; import { Ref, computed, onMounted, provide, reactive, ref, watch } from "vue"; import useStore from "../store"; @@ -202,6 +203,7 @@ onMounted(() => { findBlock, ); setPanAndZoom(canvasEl, canvasContainerEl, canvasProps); + useBlockEventHandlers(); }); const handleClick = (ev: MouseEvent) => { diff --git a/frontend/src/components/TextBlock.vue b/frontend/src/components/TextBlock.vue index 5363732a..d0b26936 100644 --- a/frontend/src/components/TextBlock.vue +++ b/frontend/src/components/TextBlock.vue @@ -1,11 +1,5 @@ diff --git a/frontend/src/components/Modals/NewComponent.vue b/frontend/src/components/Modals/NewComponent.vue new file mode 100644 index 00000000..a4a3488d --- /dev/null +++ b/frontend/src/components/Modals/NewComponent.vue @@ -0,0 +1,67 @@ + + From 8c1f81c89a07d5ca880758ae74beac0bcaa9c8a2 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 17 Dec 2024 08:30:15 +0530 Subject: [PATCH 076/118] fix: Flex defaults --- frontend/src/components/BlockFlexLayoutHandler.vue | 3 ++- frontend/src/components/BlockProperties.vue | 2 +- frontend/src/components/PlacementControl.vue | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/BlockFlexLayoutHandler.vue b/frontend/src/components/BlockFlexLayoutHandler.vue index 85a9af0b..a41ed440 100644 --- a/frontend/src/components/BlockFlexLayoutHandler.vue +++ b/frontend/src/components/BlockFlexLayoutHandler.vue @@ -6,7 +6,7 @@ { label: 'Horizontal', value: 'row', icon: 'arrow-right', hideLabel: true }, { label: 'Vertical', value: 'column', icon: 'arrow-down', hideLabel: true }, ]" - :modelValue="blockController.getStyle('flexDirection') || 'column'" + :modelValue="blockController.getStyle('flexDirection') || 'row'" @update:modelValue=" (val: string | number) => blockController.setStyle('flexDirection', val) "> @@ -17,6 +17,7 @@ type="select" label="Distribution" :options="[ + { label: '', value: '' }, { label: 'Space Between', value: 'space-between' }, { label: 'Space Around', value: 'space-around' }, { label: 'Space Evenly', value: 'space-evenly' }, diff --git a/frontend/src/components/BlockProperties.vue b/frontend/src/components/BlockProperties.vue index b3347582..89374752 100644 --- a/frontend/src/components/BlockProperties.vue +++ b/frontend/src/components/BlockProperties.vue @@ -392,7 +392,7 @@ const layoutSectionProperties = [ value: "grid", }, ], - modelValue: blockController.getStyle("display") || "flex", + modelValue: blockController.getStyle("display"), }; }, searchKeyWords: "Layout, Display, Flex, Grid, Flexbox, Flex Box, FlexBox", diff --git a/frontend/src/components/PlacementControl.vue b/frontend/src/components/PlacementControl.vue index 03505581..da4d9c80 100644 --- a/frontend/src/components/PlacementControl.vue +++ b/frontend/src/components/PlacementControl.vue @@ -98,9 +98,9 @@ const placementOptions = [ "bottom-right", ]; -const direction = computed(() => blockController.getStyle("flexDirection") as string); -const justifyContent = computed(() => blockController.getStyle("justifyContent") as string); -const alignItems = computed(() => blockController.getStyle("alignItems") as string); +const direction = computed(() => (blockController.getStyle("flexDirection") || "row") as string); +const justifyContent = computed(() => (blockController.getStyle("justifyContent") || "flex-start") as string); +const alignItems = computed(() => (blockController.getStyle("alignItems") || "stretch") as string); const setAlignment = (alignment: string, spaceBetween: boolean = false) => { switch (alignment) { From 5d05b74f1665c96c89510064c60491478436e05e Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Tue, 17 Dec 2024 08:52:45 +0530 Subject: [PATCH 077/118] fix: Handle fallback values --- frontend/src/components/BlockFlexLayoutHandler.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/BlockFlexLayoutHandler.vue b/frontend/src/components/BlockFlexLayoutHandler.vue index a41ed440..0d23dd8c 100644 --- a/frontend/src/components/BlockFlexLayoutHandler.vue +++ b/frontend/src/components/BlockFlexLayoutHandler.vue @@ -13,7 +13,7 @@ Date: Tue, 17 Dec 2024 10:20:07 +0530 Subject: [PATCH 078/118] ci: Update server-tests.yml --- .github/workflows/server-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml index a21499e4..66b137a2 100644 --- a/.github/workflows/server-tests.yml +++ b/.github/workflows/server-tests.yml @@ -29,7 +29,7 @@ jobs: ports: - 12000:6379 mariadb: - image: mariadb:10.6 + image: mariadb:11.3 env: MYSQL_ROOT_PASSWORD: root ports: From 518afc692e7ac84dfbf7341b3f5014dd962584d6 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 18 Dec 2024 08:43:21 +0530 Subject: [PATCH 079/118] chore: Update README Add docker setup guide --- README.md | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d67a330a..a58fdd0a 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,31 @@ The script will set up a production-ready instance of Frappe Builder with all th ## Getting Started (Development) +### Docker + +You need Docker, docker-compose and git setup on your machine. Refer [Docker documentation](https://docs.docker.com/). After that, follow below steps: + +**Step 1**: Setup folder and download the required files + + mkdir frappe-builder + cd frappe-builder + +**Step 2**: Download the required files + + wget -O docker-compose.yml https://raw.githubusercontent.com/frappe/builder/develop/docker/docker-compose.yml + wget -O init.sh https://raw.githubusercontent.com/frappe/builder/develop/docker/init.sh + +**Step 3**: Run the container + + docker compose up + + +Wait until the setup script creates a site and you see `Current Site set to builder.localhost` in the terminal. Once done, the site [http://builder.localhost:8000](http://builder.localhost:8000) should now be available. + +The default credentials are: +> username: administrator +> password: admin + ### Local Setup 1. [Setup Bench](https://docs.frappe.io/framework/user/en/installation). @@ -100,18 +125,19 @@ The script will set up a production-ready instance of Frappe Builder with all th 1. Open a new terminal session and cd into `frappe-bench` directory and run following commands: ```sh $ bench get-app builder - $ bench new-site sitename.localhost --install-app builder - $ bench browse sitename.localhost --user Administrator + $ bench new-site builder.localhost --install-app builder + $ bench browse builder.localhost --user Administrator ``` -1. Access the builder page at `sitename.localhost:8000/builder` in your web browser. +1. Access the builder page at `builder.localhost:8000/builder` in your web browser. **For Frontend Development** -1. Open a new terminal session and cd into `frappe-bench/apps/builder`, and run the following commands: +1. Open a new terminal session and run the following commands: ``` + cd frappe-bench/apps/builder yarn install - yarn dev + yarn dev --host ``` -1. Now, you can access the site on vite dev server at `http://sitename.localhost:8080` +1. Now, you can access the site on vite dev server at `http://builder.localhost:8080` **Note:** You'll find all the code related to Builder's frontend inside `frappe-bench/apps/builder/frontend` @@ -124,7 +150,7 @@ The script will set up a production-ready instance of Frappe Builder with all th - [Documentation](https://docs.frappe.io/builder) - [Figma Plugin (Beta)](https://www.figma.com/community/plugin/1417835732014419099/figma-to-frappe-builder) -

+

From 8f787ce62b2215eda81fe3f2d722345585a2ce51 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 18 Dec 2024 09:08:11 +0530 Subject: [PATCH 080/118] chore: Expose development port - Simpify docker setup guide - Disable auto importing of "createApp" by moving the import statement to the top of file. It used to result in failure inside docker for some reason --- README.md | 23 +++++++++-------------- docker/docker-compose.yml | 1 + frontend/src/main.ts | 3 ++- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index a58fdd0a..b6e19ccb 100644 --- a/README.md +++ b/README.md @@ -95,27 +95,22 @@ The script will set up a production-ready instance of Frappe Builder with all th ### Docker -You need Docker, docker-compose and git setup on your machine. Refer [Docker documentation](https://docs.docker.com/). After that, follow below steps: +You need Docker, docker-compose and git setup on your machine. Refer [Docker documentation](https://docs.docker.com/). After that, run following command: **Step 1**: Setup folder and download the required files - mkdir frappe-builder - cd frappe-builder - -**Step 2**: Download the required files - + mkdir frappe-builder && cd frappe-builder wget -O docker-compose.yml https://raw.githubusercontent.com/frappe/builder/develop/docker/docker-compose.yml wget -O init.sh https://raw.githubusercontent.com/frappe/builder/develop/docker/init.sh -**Step 3**: Run the container +**Step 2**: Run the container docker compose up - -Wait until the setup script creates a site and you see `Current Site set to builder.localhost` in the terminal. Once done, the site [http://builder.localhost:8000](http://builder.localhost:8000) should now be available. +Wait until the setup script creates a site and you see `Current Site set to builder.localhost` in the terminal. Once done, the site [http://builder.localhost:8000](http://builder.localhost:8000) should now be available. The default credentials are: -> username: administrator +> username: Administrator > password: admin ### Local Setup @@ -123,20 +118,20 @@ The default credentials are: 1. [Setup Bench](https://docs.frappe.io/framework/user/en/installation). 1. In the frappe-bench directory, run `bench start` and keep it running. 1. Open a new terminal session and cd into `frappe-bench` directory and run following commands: - ```sh +```bash $ bench get-app builder $ bench new-site builder.localhost --install-app builder $ bench browse builder.localhost --user Administrator - ``` +``` 1. Access the builder page at `builder.localhost:8000/builder` in your web browser. **For Frontend Development** 1. Open a new terminal session and run the following commands: - ``` +```bash cd frappe-bench/apps/builder yarn install yarn dev --host - ``` +``` 1. Now, you can access the site on vite dev server at `http://builder.localhost:8080` **Note:** You'll find all the code related to Builder's frontend inside `frappe-bench/apps/builder/frontend` diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 3fcb111d..a0e5e2c6 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -26,6 +26,7 @@ services: ports: - 8000:8000 - 9000:9000 + - 8080:8080 volumes: mariadb-data: diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 923950b0..7af9bb4e 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,6 +1,7 @@ +import { createApp } from "vue"; + import { Button, Dialog, FeatherIcon, FormControl, FrappeUI } from "frappe-ui"; import { createPinia } from "pinia"; -import { createApp } from "vue"; import "./index.css"; import router from "./router"; import "./setupFrappeUIResource"; From 73bf5c4783a6c74d2085a48d16727c951772c977 Mon Sep 17 00:00:00 2001 From: Suraj Shetty <13928957+surajshetty3416@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:16:10 +0530 Subject: [PATCH 081/118] chore: Update README.md Fix formatting --- README.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b6e19ccb..7d0d0276 100644 --- a/README.md +++ b/README.md @@ -99,19 +99,23 @@ You need Docker, docker-compose and git setup on your machine. Refer [Docker doc **Step 1**: Setup folder and download the required files - mkdir frappe-builder && cd frappe-builder - wget -O docker-compose.yml https://raw.githubusercontent.com/frappe/builder/develop/docker/docker-compose.yml - wget -O init.sh https://raw.githubusercontent.com/frappe/builder/develop/docker/init.sh +```bash +mkdir frappe-builder && cd frappe-builder +wget -O docker-compose.yml https://raw.githubusercontent.com/frappe/builder/develop/docker/docker-compose.yml +wget -O init.sh https://raw.githubusercontent.com/frappe/builder/develop/docker/init.sh +``` **Step 2**: Run the container - docker compose up +```bash +docker compose up +``` Wait until the setup script creates a site and you see `Current Site set to builder.localhost` in the terminal. Once done, the site [http://builder.localhost:8000](http://builder.localhost:8000) should now be available. -The default credentials are: -> username: Administrator -> password: admin +**Credentials:** +Username: `Administrator` +Password: `admin` ### Local Setup @@ -119,18 +123,18 @@ The default credentials are: 1. In the frappe-bench directory, run `bench start` and keep it running. 1. Open a new terminal session and cd into `frappe-bench` directory and run following commands: ```bash - $ bench get-app builder - $ bench new-site builder.localhost --install-app builder - $ bench browse builder.localhost --user Administrator +bench get-app builder +bench new-site builder.localhost --install-app builder +bench browse builder.localhost --user Administrator ``` 1. Access the builder page at `builder.localhost:8000/builder` in your web browser. **For Frontend Development** 1. Open a new terminal session and run the following commands: ```bash - cd frappe-bench/apps/builder - yarn install - yarn dev --host +cd frappe-bench/apps/builder +yarn install +yarn dev --host ``` 1. Now, you can access the site on vite dev server at `http://builder.localhost:8080` From 93556ad80a2178128f6bbe0747f4b3b310be0f43 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 18 Dec 2024 11:59:55 +0530 Subject: [PATCH 082/118] fix: Undo/Redo while duplicating a block --- frontend/src/components/BlockLayers.vue | 2 -- frontend/src/utils/block.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/components/BlockLayers.vue b/frontend/src/components/BlockLayers.vue index e2a4f63a..019e042a 100644 --- a/frontend/src/components/BlockLayers.vue +++ b/frontend/src/components/BlockLayers.vue @@ -204,9 +204,7 @@ const blockExitsInTree = (block: Block) => { }; const selectBlock = (block: Block, event: MouseEvent) => { - const pauseId = store.activeCanvas?.history?.pause(); store.selectBlock(block, event, false, true); - pauseId && store.activeCanvas?.history?.resume(pauseId); }; defineExpose({ diff --git a/frontend/src/utils/block.ts b/frontend/src/utils/block.ts index 05bdb140..03892844 100644 --- a/frontend/src/utils/block.ts +++ b/frontend/src/utils/block.ts @@ -755,9 +755,9 @@ class Block implements BlockOptions { nextTick(() => { if (child) { child.selectBlock(); + pauseId && store.activeCanvas?.history?.resume(pauseId, true); } }); - pauseId && store.activeCanvas?.history?.resume(pauseId, true); } getPadding() { const padding = this.getStyle("padding") || "0px"; From a4df15c7b12ac8907a5f52a6ce082717a0024387 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 18 Dec 2024 12:13:26 +0530 Subject: [PATCH 083/118] fix: Clear pauseIdSet once history tracking is resumed --- frontend/src/utils/useCanvasHistory.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/utils/useCanvasHistory.ts b/frontend/src/utils/useCanvasHistory.ts index e25da19e..ad681c48 100644 --- a/frontend/src/utils/useCanvasHistory.ts +++ b/frontend/src/utils/useCanvasHistory.ts @@ -137,16 +137,15 @@ export function useCanvasHistory(source: Ref, selectedBlockIds: Ref { - // console.log("resuming...", pauseId); if (pauseId && pauseIdSet.has(pauseId)) { pauseIdSet.delete(pauseId); } else if (!force) { return; } - if (pauseIdSet.size && !force) { return; } + pauseIdSet.clear(); resumeTracking(); if (commitNow) commit(); }); From a374b852bed3ebbeb750fe54844482bc06836452 Mon Sep 17 00:00:00 2001 From: Suraj Shetty Date: Wed, 18 Dec 2024 12:48:15 +0530 Subject: [PATCH 084/118] fix: Keep resizer full height always closes: https://github.com/frappe/builder/issues/269 --- frontend/src/components/BuilderLeftPanel.vue | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/BuilderLeftPanel.vue b/frontend/src/components/BuilderLeftPanel.vue index 8a9a4dce..529be003 100644 --- a/frontend/src/components/BuilderLeftPanel.vue +++ b/frontend/src/components/BuilderLeftPanel.vue @@ -1,5 +1,10 @@