Been looking here for how to add my own custom app icon and haven’t seen anything beneficial so I started working through AI (don’t hate me) and figured out the answer.
What we are going to do is add (and remove) your svg symbol to the sites/assets/frappe/icons/timeless/icons.svg so when you create a new workspace it will appear in the icon list. I’m going to give you y setup, you can feel free to change folders and names as you see fit.
First of all, you need an svg icon.
Drop your icon in your custom app
public/iconsfolder. Mine is named
You will need to modify you svg as a symbol. What I did is removed all the <xml headers and tags and renamed my
- Look at the frappe
sites/assets/frappe/icons/timeless/icons.svgfile to see some of the icon symbols there to get a good idea of the <symbol …> attributes.
- set YOUR symbol viewBox attribute something like this: viewBox=“0 0 16 16”. I don’t know how much this matters but most of the other symbols in the icons.svg file have this attribute setting.
IMPORTANT: Set the symbol icon id attribute exactly like this (with your id name)
<symbol id="icon-qor"with the rest of the attributes to follow. This is what we will be setting up as a search string later to remove the icon on uninstall.
- You probably should put a single tab in front of all your symbol code so it formats nicely in the icons.svg when it is inserted.
it should lok like this:
Create a post-install and pre-uninstall def in whatever files suits you. I did it in a setup folder:
In your post-iinstall file we will write your icon svg file to the end of the frappe icons.svg. Change the qorpay stuff to your own names.
import frappe import os import re def post_install(): """ Append the SVG symbol file to the sites/assets/frappe/icons/timeless/icons.svg file. """ src_path = os.path.join(frappe.get_app_path('qorpay'), 'public', 'icons', 'qorpay.svg') dest_path = os.path.join(os.path.dirname(frappe.get_site_path()), 'assets', 'frappe', 'icons', 'timeless', 'icons.svg') with open(dest_path, 'r+') as f: content = f.read() # Find the closing </svg> tag. m = re.search(r'</svg>', content) if m: # Append the SVG symbol file to the content. content = content[:m.start()] + open(src_path, 'r').read() + content[m.start():] f.seek(0) f.write(content) f.truncate()
- In the pre-uninstall file we will write the code to remove your icon symbol from the frappe icons.svg. NOTE the line
m = re.search(r'<symbol id="icon-qor"(.|\n)*</symbol>', content). This searches the icon svg for a match then will delete the match. This is why it is important to have your id attribute right after the <symbol id=“XXX”. BTW the
(.|\n)*tells the search to include all tabs, spaces and newlines before the ending
import frappe import os import re def pre_uninstall(): """ Remove the SVG symbol file from the sites/assets/frappe/icons/timeless/icons.svg file by ID. """ src_path = os.path.join(os.path.dirname(frappe.get_site_path()), 'assets', 'frappe', 'icons', 'timeless', 'icons.svg') with open(src_path, 'r+') as f: content = f.read() # Find the symbol tag with the specified ID. m = re.search(r'<symbol id="icon-qor"(.|\n)*</symbol>', content) if m: # Remove the symbol tag from the content. content = content[:m.start()] + content[m.end():] f.seek(0) f.write(content) f.truncate()
- Finally, in your custom app hooks.py file make sure you point to your post-install and pre-uninstall defs:
That should be it. When you do a
bench --site install-app <your app> check the
sites/assets/frappe/icons/timeless/icons.svg to see your symbol at the end of the file. Do an uninstall then check the
sites/assets/frappe/icons/timeless/icons.svg again to make sure your symbol is removed.
If you create a PUBLIc workspace for your custom app with it’s own icon, assigned to your custom app module the workspace menu name/icon should show up on app installs.
- You may need to reload your site after install before seeing the icon in the workspace icon list.
- HELP: If
bench updateis run the post_install does not run AFAIK. Thinking maybe can run a patch to update the icon again after an update but haven’t made it that far in my learning. So on update will have to manually copy your svg into the icons.svg until one of you have a way to ensure the icon is updated on bench updates.