Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: frappe/builder
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.12.4
Choose a base ref
...
head repository: frappe/builder
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Loading
Showing with 7,768 additions and 4,448 deletions.
  1. +1 −0 .git-blame-ignore-revs
  2. +0 −4 .github/helper/install_dependencies.sh
  3. +60 −0 .github/workflows/docker-image.yml
  4. +4 −4 .github/workflows/server-tests.yml
  5. +126 −68 README.md
  6. +1 −1 builder/__init__.py
  7. +50 −0 builder/api.py
  8. +16 −16 builder/builder/doctype/builder_client_script/builder_client_script.js
  9. +3 −2 builder/builder/doctype/builder_client_script/builder_client_script.json
  10. +3 −2 builder/builder/doctype/builder_component/builder_component.json
  11. +161 −0 builder/builder/doctype/builder_component/builder_component.py
  12. +2 −2 builder/builder/doctype/builder_component/patches/set_component_id.py
  13. +25 −2 builder/builder/doctype/builder_page/builder_page.json
  14. +103 −12 builder/builder/doctype/builder_page/builder_page.py
  15. +24 −15 builder/builder/doctype/builder_page/patches/attach_client_script_to_builder_page.py
  16. +40 −18 builder/builder/doctype/builder_page/patches/properly_extend_blocks_from_component.py
  17. +41 −10 builder/builder/doctype/builder_page/patches/script_to_update_links.py
  18. +18 −1 builder/builder/doctype/builder_page/test_builder_page.py
  19. +1 −1 builder/builder/doctype/builder_page_client_script/builder_page_client_script.py
  20. 0 frontend/src/utils/blockOperations.ts → builder/builder/doctype/builder_page_library/__init__.py
  21. +47 −0 builder/builder/doctype/builder_page_library/builder_page_library.json
  22. +9 −0 builder/builder/doctype/builder_page_library/builder_page_library.py
  23. 0 builder/builder/doctype/builder_project_folder/__init__.py
  24. +8 −0 builder/builder/doctype/builder_project_folder/builder_project_folder.js
  25. +56 −0 builder/builder/doctype/builder_project_folder/builder_project_folder.json
  26. +9 −0 builder/builder/doctype/builder_project_folder/builder_project_folder.py
  27. +96 −4 builder/builder/doctype/builder_settings/builder_settings.js
  28. +19 −2 builder/builder/doctype/builder_settings/builder_settings.json
  29. +53 −0 builder/builder/doctype/builder_settings/builder_settings.py
  30. +3 −2 builder/builder/doctype/user_font/user_font.json
  31. +1 −3 builder/builder/patches/rename_web_page_beta_to_builder_page.py
  32. +8 −8 builder/builder/test_utils.py
  33. +5 −6 builder/html_preview_image.py
  34. +3 −3 builder/public/js/builder.js
  35. +3 −0 builder/templates/generators/webpage.html
  36. +5 −2 builder/templates/generators/webpage_scripts.html
  37. +5 −5 builder/utils.py
  38. +1 −0 docker/docker-compose.yml
  39. +1 −1 frappe-ui
  40. +1 −1 frontend/cypress.config.js
  41. +1 −1 frontend/cypress/support/commands.js
  42. +2 −2 frontend/cypress/support/e2e.js
  43. +0 −83 frontend/espresso_colors.js
  44. +1 −1 frontend/package.json
  45. +19 −5 frontend/src/App.vue
  46. +2 −1 frontend/src/builder.d.ts
  47. +0 −152 frontend/src/colors.css
  48. +2 −7 frontend/src/components/AlertDialog.vue
  49. +2 −2 frontend/src/components/AppsMenu.vue
  50. +3 −7 frontend/src/components/BackgroundHandler.vue
  51. +63 −185 frontend/src/components/BlockContextMenu.vue
  52. +50 −41 frontend/src/components/BlockEditor.vue
  53. +4 −3 frontend/src/components/BlockFlexLayoutHandler.vue
  54. +1 −1 frontend/src/components/BlockHTML.vue
  55. +87 −72 frontend/src/components/BlockLayers.vue
  56. +6 −7 frontend/src/components/BlockPositionHandler.vue
  57. +28 −1,222 frontend/src/components/BlockProperties.vue
  58. +26 −0 frontend/src/components/BlockPropertySections/CustomAttributesSection.ts
  59. +55 −0 frontend/src/components/BlockPropertySections/DataKeySection.ts
  60. +78 −0 frontend/src/components/BlockPropertySections/DimenstionSection.ts
  61. +87 −0 frontend/src/components/BlockPropertySections/ImageOptionsSection.ts
  62. +63 −0 frontend/src/components/BlockPropertySections/LayoutSection.ts
  63. +71 −0 frontend/src/components/BlockPropertySections/LinkSection.ts
  64. +239 −0 frontend/src/components/BlockPropertySections/OptionsSection.ts
  65. +26 −0 frontend/src/components/BlockPropertySections/PositionSection.ts
  66. +38 −0 frontend/src/components/BlockPropertySections/RawStyleSection.ts
  67. +45 −0 frontend/src/components/BlockPropertySections/SpacingSection.ts
  68. +192 −0 frontend/src/components/BlockPropertySections/StyleSection.ts
  69. +203 −0 frontend/src/components/BlockPropertySections/TypographySection.ts
  70. +130 −0 frontend/src/components/BlockPropertySections/VideoOptionsSection.ts
  71. +75 −72 frontend/src/components/BorderRadiusHandler.vue
  72. +11 −2 frontend/src/components/BoxResizer.vue
  73. +48 −35 frontend/src/components/BuilderAssets.vue
  74. +3 −72 frontend/src/components/BuilderBlock.vue
  75. +6 −4 frontend/src/components/BuilderBlockTemplates.vue
  76. +153 −653 frontend/src/components/BuilderCanvas.vue
  77. +25 −34 frontend/src/components/BuilderLeftPanel.vue
  78. +27 −32 frontend/src/components/BuilderToolbar.vue
  79. +3 −4 frontend/src/components/CollapsibleSection.vue
  80. +5 −10 frontend/src/components/ContextMenu.vue
  81. +4 −4 frontend/src/components/Controls/Autocomplete.vue
  82. +5 −2 frontend/src/components/Controls/BuilderButton.vue
  83. +35 −4 frontend/src/components/Controls/CodeEditor.vue
  84. +5 −6 frontend/src/components/Controls/ColorPicker.vue
  85. +65 −0 frontend/src/components/Controls/Dialog.vue
  86. +1 −1 frontend/src/components/Controls/FontUploader.vue
  87. +18 −18 frontend/src/components/Controls/Input.vue
  88. +1 −2 frontend/src/components/Controls/InputLabel.vue
  89. +1 −1 frontend/src/components/Controls/OptionToggle.vue
  90. +1 −1 frontend/src/components/Controls/Switch.vue
  91. +142 −0 frontend/src/components/DashboardSidebar.vue
  92. +92 −0 frontend/src/components/EditableSpan.vue
  93. +10 −0 frontend/src/components/Icons/Files.vue
  94. +9 −0 frontend/src/components/Icons/Folder.vue
  95. +8 −22 frontend/src/components/Icons/Loading.vue
  96. +3 −8 frontend/src/components/ImageUploadInput.vue
  97. +8 −4 frontend/src/components/MainMenu.vue
  98. +80 −0 frontend/src/components/Modals/NewBlockTemplate.vue
  99. +72 −0 frontend/src/components/Modals/NewComponent.vue
  100. +53 −0 frontend/src/components/Modals/NewFolder.vue
  101. +41 −0 frontend/src/components/Modals/PageListModal.vue
  102. +53 −0 frontend/src/components/Modals/SelectFolder.vue
  103. +6 −14 frontend/src/components/ObjectEditor.vue
  104. +5 −5 frontend/src/components/PaddingHandler.vue
  105. +72 −0 frontend/src/components/PageCard.vue
  106. +54 −27 frontend/src/components/PageClientScriptManager.vue
  107. +90 −0 frontend/src/components/PageListItem.vue
  108. +1 −1 frontend/src/components/PageOptions.vue
  109. +19 −5 frontend/src/components/PageScript.vue
  110. +1 −1 frontend/src/components/PanelResizer.vue
  111. +10 −10 frontend/src/components/PlacementControl.vue
  112. +67 −0 frontend/src/components/PublishButton.vue
  113. +7 −5 frontend/src/components/Settings.vue
  114. +20 −2 frontend/src/components/Settings/GlobalCode.vue
  115. +6 −5 frontend/src/components/Settings/GlobalGeneral.vue
  116. +4 −4 frontend/src/components/Settings/GlobalRedirects.vue
  117. +68 −0 frontend/src/components/Settings/PageCode.vue
  118. +70 −46 frontend/src/components/Settings/PageGeneral.vue
  119. +4 −4 frontend/src/components/Settings/PageMeta.vue
  120. +2 −4 frontend/src/components/Settings/PageRedirects.vue
  121. +108 −59 frontend/src/components/TextBlock.vue
  122. +13 −0 frontend/src/data/builderPageLibrary.ts
  123. +14 −0 frontend/src/data/builderProjectFolder.ts
  124. +1 −0 frontend/src/data/webPage.ts
  125. +21 −0 frontend/src/directives/vOnClickAndHold.ts
  126. +4 −1 frontend/src/index.css
  127. +0 −1 frontend/src/lib.d.ts
  128. +4 −3 frontend/src/main.ts
  129. +92 −445 frontend/src/pages/PageBuilder.vue
  130. +349 −332 frontend/src/pages/PageBuilderDashboard.vue
  131. +26 −38 frontend/src/pages/PagePreview.vue
  132. +30 −24 frontend/src/router.ts
  133. +156 −135 frontend/src/store.ts
  134. +25 −0 frontend/src/types/Builder/BuilderCanvas.ts
  135. +6 −0 frontend/src/types/Builder/BuilderPage.ts
  136. +19 −0 frontend/src/types/Builder/BuilderPageLibrary.ts
  137. +15 −0 frontend/src/types/Builder/BuilderProjectFolder.ts
  138. +4 −0 frontend/src/types/Builder/BuilderSettings.ts
  139. +95 −67 frontend/src/utils/block.ts
  140. +25 −3 frontend/src/utils/blockTemplate.ts
  141. +87 −13 frontend/src/utils/helpers.ts
  142. +0 −2 frontend/src/utils/panAndZoom.ts
  143. +0 −1 frontend/src/utils/realtimeHandler.ts
  144. +93 −0 frontend/src/utils/useBlockEventHandlers.ts
  145. +86 −0 frontend/src/utils/useBlockSelection.ts
  146. +506 −0 frontend/src/utils/useBuilderEvents.ts
  147. +271 −0 frontend/src/utils/useCanvasDropZone.ts
  148. +233 −0 frontend/src/utils/useCanvasEvents.ts
  149. +171 −0 frontend/src/utils/useCanvasHistory.ts
  150. +292 −0 frontend/src/utils/useCanvasUtils.ts
  151. +192 −0 frontend/src/utils/useComponentStore.ts
  152. +2 −2 frontend/src/utils/useDraggableBlock.ts
  153. +2 −5 frontend/tailwind.config.js
  154. +721 −206 yarn.lock
1 change: 1 addition & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
b3ddeda50bf11d04ee3b82f38af7355aad006fe0
4 changes: 0 additions & 4 deletions .github/helper/install_dependencies.sh
Original file line number Diff line number Diff line change
@@ -3,10 +3,6 @@ set -e

echo "Setting Up System Dependencies..."

sudo apt update
sudo apt remove mysql-server mysql-client
sudo apt install libcups2-dev redis-server mariadb-client-10.6

install_wkhtmltopdf() {
wget -q https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb
sudo apt install ./wkhtmltox_0.12.6-1.focal_amd64.deb
60 changes: 60 additions & 0 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: Build Container Image
on:
workflow_dispatch:
push:
branches:
- master
- develop
tags:
- "*"

jobs:
build:
name: Build

runs-on: ubuntu-latest

steps:
- name: Checkout Entire Repository
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64

- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set Branch
run: |
export APPS_JSON='[{"url": "https://github.com/frappe/builder","branch": "${{ github.ref_name }}"}]'
echo "APPS_JSON_BASE64=$(echo $APPS_JSON | base64 -w 0)" >> $GITHUB_ENV
echo "FRAPPE_BRANCH=${{ github.ref_type == 'tag' || github.ref_name == 'master' && 'version-15' || 'develop' }}" >> $GITHUB_ENV
- name: Set Image Tag
run: |
echo "IMAGE_TAG=${{ github.ref_name == 'develop' && 'develop' || 'stable' }}" >> $GITHUB_ENV
- uses: actions/checkout@v4
with:
repository: frappe/frappe_docker
path: builds

- name: Build and push
uses: docker/build-push-action@v6
with:
push: true
context: builds
file: builds/images/layered/Containerfile
tags: >
ghcr.io/${{ github.repository }}:${{ github.ref_name }},
ghcr.io/${{ github.repository }}:${{ env.IMAGE_TAG }}
build-args: |
"FRAPPE_BRANCH=${{ env.FRAPPE_BRANCH }}"
"APPS_JSON_BASE64=${{ env.APPS_JSON_BASE64 }}"
8 changes: 4 additions & 4 deletions .github/workflows/server-tests.yml
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ jobs:
ports:
- 12000:6379
mariadb:
image: mariadb:10.6
image: mariadb:10.8
env:
MYSQL_ROOT_PASSWORD: root
ports:
@@ -100,7 +100,7 @@ jobs:
TYPE: server

- name: Upload coverage data
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.container }}
path: /home/runner/frappe-bench/sites/coverage.xml
@@ -114,10 +114,10 @@ jobs:
uses: actions/checkout@v3

- name: Download artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4

- name: Upload coverage data
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
name: Server
token: ${{ secrets.CODECOV_TOKEN }}
194 changes: 126 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,104 +1,162 @@
<div align="center">
<a href="https://frappe.io/products/builder">
<img src="https://raw.githubusercontent.com/frappe/builder/master/frontend/public/builder_logo.png" height="80" alt="Frappe Builder Logo">
</a>
<h2>Frappe Builder</h2>
<p>Crafting Web Pages Made Effortless!</p>

![Frappe Builder](https://github.com/user-attachments/assets/e906545e-101e-4d55-8a25-2c4f6380ea5e)
[Web page design credit](https://www.figma.com/community/file/949266436474872912)

<a href="https://frappe.io/products/builder">
<img src="https://raw.githubusercontent.com/frappe/builder/master/frontend/public/builder_logo.png" height="80" alt="Frappe Builder Logo">
</a>


<h1>Frappe Builder</h1>

**Crafting Web Pages Made Effortless**


![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)

<div>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/7b013cc1-fe40-4b3c-a765-d8c3697bf81e">
<img width="1402" alt="Frappe Builder Screenshot" src="https://github.com/user-attachments/assets/d20cec8a-9e30-4ad5-9fc0-9c136fffa916">
</picture>
</div>

[Website](https://frappe.io/builder) - [Documentation](https://docs.frappe.io/builder)
</div>

# Frappe Builder
## Frappe Builder

Frappe Builder is a low-code website builder designed for simplicity, speed, and flexibility. Craft beautiful websites effortlessly with an intuitive visual builder. Whether you're a designer looking for ease or a developer seeking customization, Frappe Builder empowers you. It also features a click-to-publish option that gives you the complete end-to-end website creation experience.

## Key Features
### Motivation

- **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.
- **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.
- **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.
Most existing solutions were either too complex, too restrictive, or difficult to integrate with the Frappe ecosystem. Additionally, pages built with these tools were often bloated with unnecessary scripts and styles. I wanted to take a stab at solving this problem while prioritising performance from day one. I aimed to address two major issues with this project: providing an intuitive way to design a web page and enabling one-click publishing. As a web developer, it helps me scratch my own itch, and I hope it helps others too.

## Getting Started
### Key Features

### Managed Hosting
-**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 are highly performant, consistently scoring high on Google Lighthouse tests.
- 🧰 **Production Ready**: [Frappe.io](https://frappe.io) built on Frappe Builder, stands as a testament to its reliability in delivering production-ready solutions.

Get started with your personal or business site with a few clicks on [Frappe Cloud](https://frappecloud.com/builder/signup).
### Under the Hood

### Docker (Recommended)
- [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.

The quickest way to set up Frappe Builder and take it for a test ride.

Frappe framework is multi-tenant and supports multiple apps by default. This docker compose is just a standalone version with Frappe Builder pre-installed. Just put it behind your desired reverse-proxy if needed, and you're good to go.

If you wish to use multiple Frappe apps or need multi-tenancy. Take a look at our production ready self-hosted workflow, or join us on Frappe Cloud to get first party support and hassle-free hosting.

**Step 1**: Setup folder and download the required files
## Getting Started (Production)

mkdir frappe-builder
cd frappe-builder
### Managed Hosting

**Step 2**: Download the required files
Get started with your personal or business site with a few clicks on Frappe Cloud - our official hosting service.
<div>
<a href="https://frappecloud.com/builder/signup" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://frappe.io/files/try-on-fc-white.png">
<img src="https://frappe.io/files/try-on-fc-black.png" alt="Try on Frappe Cloud" height="28" />
</picture>
</a>
</div>

Docker Compose File:

wget -O docker-compose.yml https://raw.githubusercontent.com/frappe/builder/develop/docker/docker-compose.yml
### Self Hosting

Frappe Builder bench setup script
Follow these steps to set up Frappe Builder in production:

wget -O init.sh https://raw.githubusercontent.com/frappe/builder/develop/docker/init.sh
**Step 1**: Download the easy install script

**Step 3**: Run the container and daemonize it
```bash
wget https://frappe.io/easy-install.py
```

docker compose up -d
**Step 2**: Run the deployment command

**Step 4**: The site [http://builder.localhost](http://builder.localhost) should now be available. The default credentials are:
```bash
python3 ./easy-install.py deploy \
--project=builder_prod_setup \
--email=email@example.com \
--image=ghcr.io/frappe/builder \
--version=stable \
--app=builder \
--sitename subdomain.domain.tld
```

> username: administrator
> password: admin
Replace the following parameters with your values:
- `email@example.com`: Your email address
- `subdomain.domain.tld`: Your domain name where Builder will be hosted

### Self-hosting
The script will set up a production-ready instance of Frappe Builder with all the necessary configurations in about 5 minutes.

If you prefer self-hosting, follow the official [Frappe Bench Installation](https://github.com/frappe/bench#installation) instructions.
## Getting Started (Development)

## Want to just try out or contribute?
### Docker

### Codespaces
You need Docker, docker-compose and git setup on your machine. Refer [Docker documentation](https://docs.docker.com/). After that, run following command:

https://github.com/frappe/builder/assets/13928957/c96ce2ce-9eb3-4bd5-8e92-0b39d971cb00
**Step 1**: Setup folder and download the required files

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 `<random-id>.github.dev/builder` to access the builder interface.
```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
```

### Local Setup
**Step 2**: Run the container

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
```
4. Open the site in the browser:
```sh
$ bench browse sitename.localhost --user Administrator
```
5. Access the builder page at `sitename.localhost:8000/builder` in your web browser.
```bash
docker compose up
```

## Need help?
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.

Join our [telegram group](https://t.me/frappebuilder) for instant help.
**Credentials:**
Username: `Administrator`
Password: `admin`

## License
### Local Setup

[GNU Affero General Public License v3.0](LICENSE)
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:
```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`

<h2></h2>

### 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)

<br>
<br>
<div align="center">
<a href="https://frappe.io" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://frappe.io/files/Frappe-white.png">
<img src="https://frappe.io/files/Frappe-black.png" alt="Frappe Technologies" height="28"/>
</picture>
</a>
</div>
2 changes: 1 addition & 1 deletion builder/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.12.4"
__version__ = "1.15.0"
50 changes: 50 additions & 0 deletions builder/api.py
Original file line number Diff line number Diff line change
@@ -215,3 +215,53 @@ def get_apps():
app_list += filter(lambda app: app.get("name") != "builder", apps)

return app_list


@frappe.whitelist()
def update_page_folder(pages: list[str], folder_name: str) -> None:
if not frappe.has_permission("Builder Page", ptype="write"):
frappe.throw("You do not have permission to update page folder.")
for page in pages:
frappe.db.set_value("Builder Page", page, "project_folder", folder_name, update_modified=False)


@frappe.whitelist()
def duplicate_page(page_name: str):
if not frappe.has_permission("Builder Page", ptype="write"):
frappe.throw("You do not have permission to duplicate a page.")
page = frappe.get_doc("Builder Page", page_name)
new_page = frappe.copy_doc(page)
del new_page.page_name
new_page.route = None
client_scripts = page.client_scripts
new_page.client_scripts = []
for script in client_scripts:
builder_script = frappe.get_doc("Builder Client Script", script.builder_script)
new_script = frappe.copy_doc(builder_script)
new_script.name = f"{builder_script.name}-{frappe.generate_hash(length=5)}"
new_script.insert(ignore_permissions=True)
new_page.append("client_scripts", {"builder_script": new_script.name})
new_page.insert()
return new_page


@frappe.whitelist()
def delete_folder(folder_name: str) -> None:
if not frappe.has_permission("Builder Project Folder", ptype="write"):
frappe.throw("You do not have permission to delete a folder.")

# remove folder from all pages
pages = frappe.get_all("Builder Page", filters={"project_folder": folder_name}, fields=["name"])
for page in pages:
frappe.db.set_value("Builder Page", page.name, "project_folder", "", update_modified=False)

frappe.db.delete("Builder Project Folder", folder_name)


@frappe.whitelist()
def sync_component(component_id: str):
if not frappe.has_permission("Builder Page", ptype="write"):
frappe.throw("You do not have permission to sync a component.")

component = frappe.get_doc("Builder Component", component_id)
component.sync_component()
Loading