jey_theme/CLAUDE.md

85 lines
5.7 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## What this app is
Frappe/ERPNext v15 app that does three things:
1. Overrides the desk UI with a multi-theme visual system (CSS + JS bundle).
2. Hides the **Quality Management** and **Subcontracting** modules app-wide (URL/API/bootinfo/permissions).
3. Maintains a custom **Taxes Az** workspace on every migrate.
Installed into `frappe-bench` as a normal app. Python code is at `jey_theme/` (Frappe app package). Frontend assets live at `jey_theme/public/{css,js}`.
## Commands
Run from `frappe-bench/` (the bench root), not this app dir.
- `bench build --app jey_theme` — rebuild JS bundle after editing `jey_theme/public/js/jey_theme.js`.
- CSS-only changes: no build needed, just hard-reload the browser.
- `bench migrate` — runs the `after_migrate` hook that rebuilds the Taxes Az workspace from `setup/taxes_workspace.py`.
- `bench execute jey_theme.setup.taxes_workspace.setup` — re-run the workspace setup without a full migrate.
- `bench restart` — reload Python workers after editing `access_control.py` or `hooks.py`.
- No test suite, no linter config in this repo.
## Architecture
### Python: access control (`jey_theme/access_control.py` + `hooks.py`)
Goal: make blocked modules invisible and unreachable for every user, including Administrator.
- `BLOCKED_MODULES` / `BLOCKED_DOCTYPES_EXTRA` — edit these frozensets to change what's blocked.
- Three defense layers wired in `hooks.py`:
- `before_request` — blocks `/api/resource/<Doctype>`, `/app/<slug>`, and form_dict-based calls at the HTTP boundary (catches Administrator, who bypasses `has_permission`).
- `has_permission = {"*": ...}` — per-doc deny for non-admin users who have role access.
- `extend_bootinfo` — strips blocked items from `allowed_modules`, `modules`, `user.can_*`, `workspaces.pages`, `workspace_sidebar_item`, `module_wise_workspaces`, `app_data`, `desktop_icons`, etc., so the client router/sidebar never sees them.
- Slug/doctype/workspace sets are cached on `frappe.local` per-request.
- When adding a new block vector: extend `extend_bootinfo` rather than relying only on `has_permission`, because the client has many independent boot-derived UIs.
### Python: Taxes Az workspace (`jey_theme/setup/taxes_workspace.py`)
Idempotent setup run via `after_migrate`.
- Builds a `Workspace` named **Taxes Az** with six cards (Declarations, Setup, Tools, E-Taxes Setup, E-Taxes Reference, E-Taxes Documents), a `Workspace Sidebar` listing every doctype, and a `Desktop Icon` that routes via the sidebar.
- The doctype list is a **static snapshot** in `DECLARATIONS_DOCTYPES` / `SETUP_DOCTYPES` / `TOOLS_DOCTYPES` (taxes_az) and `ETAXES_SETUP_DOCTYPES` / `ETAXES_REFERENCE_DOCTYPES` / `ETAXES_DOCUMENT_DOCTYPES` (invoice_az). Adding a DocType to either app does NOT auto-include it — append to the tuple and re-migrate.
- `_cleanup_obsolete()` removes legacy docs owned by this app (currently `"Taxes"`). Only touches records where `app == "jey_theme"` — never deletes ERPNext/other-app docs.
### Frontend: multi-theme system
Bundle entry: `jey_theme/public/js/jey_theme.js`. CSS: `jey_theme/public/css/{shared,theme_chrome,theme_modern}.css`. All four are loaded via `app_include_css` / `app_include_js` in `hooks.py` for both desk and web contexts.
- Theme selector lives in `data-jey-theme` on `<html>`, stored in `localStorage("jey-theme")`. Default: `chrome`. Set before first paint by an IIFE at the top of `jey_theme.js`.
- Themes supported: **chrome** (metallic rings), **modern** (frosted glass). No dark/light variants — each theme is self-contained.
- Theme-specific CSS MUST be wrapped in `[data-jey-theme="themename"]`. Keyframes MUST be prefixed `jey-<theme>-*` to avoid cross-theme name collisions.
- Shared CSS (checkboxes, icon base sizing, switcher UI, column-resize rules) lives in `shared.css` without theme selectors.
### Frontend: per-theme icons
- `THEME_ICONS[themeName]` in `jey_theme.js` maps icon keys to inline SVG path strings. Missing keys fall back to `THEME_ICONS.chrome`, then `_fallback`.
- JS replaces `<img class="app-icon">` / `.folder-icon` with inline `<svg class="jey-icon">` per current theme.
- `window.jeyRebuildIcons()` tears down and rebuilds all icon DOM — called on theme switch.
- SVGs may carry a `cls` (e.g. `ico-buying`) for shared CSS animations.
### Frontend: early-paint tricks in `jey_theme.js`
The top IIFE runs before paint to avoid FOUC:
- Sets `data-jey-theme` immediately.
- Defaults `container_fullwidth = "true"` on fresh install.
- Reads all `jey-col-widths:<Doctype>:<field>` localStorage keys and injects a `<style id="jey-col-resize-styles">` with per-grid column widths, plus a MutationObserver that stamps `data-jey-grid` on grids as they appear.
Keep this IIFE minimal and synchronous — anything slow here delays first paint.
## Adding a new theme
1. Create `jey_theme/public/css/theme_mytheme.css` with `[data-jey-theme="mytheme"]` selectors. Prefix keyframes `jey-mytheme-*`.
2. Add `THEME_ICONS.mytheme = { ... }` in `jey_theme.js` (only override keys you care about).
3. Add an entry to `JEY_THEMES` array in the switcher section of `jey_theme.js`.
4. Add the CSS file to both `app_include_css` and `web_include_css` in `hooks.py`.
5. `bench build --app jey_theme`.
## Rules
- Themes can change anything (layout, positioning, colors, fonts, visibility, animations, DOM structure) — not just icons. Use JS (`jeyRebuildIcons` / theme-switch hooks) for DOM restructuring.
- Never add `[data-theme="dark"]` or light/dark variant rules — themes are self-contained (no inherited dark/light axis).
- Don't touch ERPNext-owned records in setup scripts; gate deletes on `app == "jey_theme"`.