claude-mpm 5.4.36__py3-none-any.whl → 5.4.62__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +5 -0
- claude_mpm/agents/PM_INSTRUCTIONS.md +489 -177
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/frontmatter_validator.py +2 -2
- claude_mpm/cli/commands/configure_agent_display.py +12 -0
- claude_mpm/cli/commands/mpm_init/core.py +72 -0
- claude_mpm/cli/commands/profile.py +276 -0
- claude_mpm/cli/commands/skills.py +14 -18
- claude_mpm/cli/executor.py +10 -0
- claude_mpm/cli/parsers/base_parser.py +7 -0
- claude_mpm/cli/parsers/profile_parser.py +147 -0
- claude_mpm/cli/parsers/skills_parser.py +0 -6
- claude_mpm/cli/startup.py +433 -147
- claude_mpm/commands/mpm-config.md +13 -250
- claude_mpm/commands/mpm-doctor.md +9 -22
- claude_mpm/commands/mpm-help.md +5 -206
- claude_mpm/commands/mpm-init.md +81 -507
- claude_mpm/commands/mpm-monitor.md +15 -402
- claude_mpm/commands/mpm-organize.md +61 -441
- claude_mpm/commands/mpm-postmortem.md +6 -108
- claude_mpm/commands/mpm-session-resume.md +12 -363
- claude_mpm/commands/mpm-status.md +5 -69
- claude_mpm/commands/mpm-ticket-view.md +52 -495
- claude_mpm/commands/mpm-version.md +5 -107
- claude_mpm/core/optimized_startup.py +61 -0
- claude_mpm/core/shared/config_loader.py +3 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.DWzvg0-y.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.ThTw9_ym.css +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{CWc5urbQ.js → 4TdZjIqw.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/5shd3_w0.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B0uc0UOD.js +36 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7RN905-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/B7xVLGWV.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BIF9m_hv.js +61 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BKjSRqUr.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BPYeabCQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BQaXIfA_.js +331 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{uj46x2Wr.js → BSNlmTZj.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Be7GpZd6.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Bh0LDWpI.js +145 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BofRWZRR.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BovzEFCE.js +30 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C30mlcqg.js +165 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4B-KCzX.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C4JcI4KD.js +122 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CBBdVcY8.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CDuw-vjf.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/C_Usid8X.js +15 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cfqx1Qun.js +10 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CiIAseT4.js +128 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CmKTTxBW.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CnA0NrzZ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cs_tUR18.js +24 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Cu_Erd72.js +261 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CyWMqx4W.js +43 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzZX-COe.js +220 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CzeYkLYB.js +65 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D3k0OPJN.js +4 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/D9lljYKQ.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DGkLK5U1.js +267 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DI7hHRFL.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DLVjFsZ3.js +139 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DUrLdbGD.js +89 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DVp1hx9R.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DY1XQ8fi.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DZX00Y4g.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Da0KfYnO.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DaimHw_p.js +68 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dfy6j1xT.js +323 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dhb8PKl3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Dle-35c7.js +64 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DmxopI1J.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DwBR2MJi.js +60 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/GYwsonyD.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/Gi6I4Gst.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{DjhvlsAc.js → NqQ1dWOy.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/RJiighC3.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/{N4qtv3Hx.js → Vzk33B_K.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/ZGh7QtNv.js +7 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bT1r9zLR.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/bTOqqlTd.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/eNVUfhuA.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/iEWssX7S.js +162 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/sQeU3Y1z.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/uuIeMWc-.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.D6-I5TpK.js +2 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.NWzMBYRp.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/{0.CAGBuiOw.js → 0.m1gL8KXf.js} +1 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.CgNOuw-d.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.C0GcWctS.js +1 -0
- claude_mpm/dashboard/static/svelte-build/_app/version.json +1 -1
- claude_mpm/dashboard/static/svelte-build/index.html +10 -10
- claude_mpm/dashboard-svelte/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/format_json.py +28 -0
- claude_mpm/dashboard-svelte/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- claude_mpm/hooks/kuzu_memory_hook.py +5 -5
- claude_mpm/init.py +276 -0
- claude_mpm/services/agents/agent_builder.py +3 -3
- claude_mpm/services/agents/deployment/agent_deployment.py +22 -0
- claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -1
- claude_mpm/services/agents/deployment/agent_format_converter.py +25 -13
- claude_mpm/services/agents/deployment/agent_template_builder.py +37 -17
- claude_mpm/services/agents/deployment/async_agent_deployment.py +31 -27
- claude_mpm/services/agents/deployment/local_template_deployment.py +3 -1
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +149 -4
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +47 -26
- claude_mpm/services/agents/git_source_manager.py +21 -2
- claude_mpm/services/agents/sources/git_source_sync_service.py +116 -5
- claude_mpm/services/monitor/management/lifecycle.py +7 -1
- claude_mpm/services/pm_skills_deployer.py +711 -0
- claude_mpm/services/profile_manager.py +337 -0
- claude_mpm/services/skills/git_skill_source_manager.py +148 -11
- claude_mpm/services/skills/selective_skill_deployer.py +97 -48
- claude_mpm/services/skills_deployer.py +161 -65
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +79 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +178 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +577 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +467 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +537 -0
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +730 -0
- claude_mpm/skills/bundled/collaboration/git-worktrees.md +317 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +112 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +146 -0
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +412 -0
- claude_mpm/skills/bundled/collaboration/stacked-prs.md +251 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +81 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +362 -0
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +312 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +152 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +668 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +587 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +438 -0
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +391 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +119 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +148 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +483 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +452 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +449 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +411 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +14 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +58 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +68 -0
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +69 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +131 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +325 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +490 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +425 -0
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +499 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/INTEGRATION.md +611 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/README.md +596 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/SKILL.md +260 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/examples/nextjs-env-structure.md +315 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/frameworks.md +436 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/security.md +433 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/synchronization.md +452 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/troubleshooting.md +404 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/references/validation.md +420 -0
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +86 -0
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +43 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +47 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +65 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +30 -0
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +16 -0
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +160 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +412 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +602 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +915 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +916 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +752 -0
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +1237 -0
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +189 -0
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +500 -0
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +464 -0
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +619 -0
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +437 -0
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +231 -0
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +170 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +602 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +821 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +742 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +726 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +764 -0
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +831 -0
- claude_mpm/skills/bundled/pm/pm-delegation-patterns/SKILL.md +167 -0
- claude_mpm/skills/bundled/pm/pm-git-file-tracking/SKILL.md +113 -0
- claude_mpm/skills/bundled/pm/pm-pr-workflow/SKILL.md +124 -0
- claude_mpm/skills/bundled/pm/pm-ticketing-integration/SKILL.md +154 -0
- claude_mpm/skills/bundled/pm/pm-verification-protocols/SKILL.md +198 -0
- claude_mpm/skills/bundled/react/flexlayout-react.md +742 -0
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +226 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +901 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +775 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +937 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +770 -0
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +961 -0
- claude_mpm/skills/bundled/security-scanning.md +112 -0
- claude_mpm/skills/bundled/tauri/tauri-async-patterns.md +495 -0
- claude_mpm/skills/bundled/tauri/tauri-build-deploy.md +599 -0
- claude_mpm/skills/bundled/tauri/tauri-command-patterns.md +535 -0
- claude_mpm/skills/bundled/tauri/tauri-error-handling.md +613 -0
- claude_mpm/skills/bundled/tauri/tauri-event-system.md +648 -0
- claude_mpm/skills/bundled/tauri/tauri-file-system.md +673 -0
- claude_mpm/skills/bundled/tauri/tauri-frontend-integration.md +767 -0
- claude_mpm/skills/bundled/tauri/tauri-performance.md +669 -0
- claude_mpm/skills/bundled/tauri/tauri-state-management.md +573 -0
- claude_mpm/skills/bundled/tauri/tauri-testing.md +384 -0
- claude_mpm/skills/bundled/tauri/tauri-window-management.md +628 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +119 -0
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +253 -0
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +145 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +543 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +741 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +470 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +458 -0
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +639 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/SKILL.md +458 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/examples/example-inspection-report.md +411 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/assertion-quality.md +317 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/inspection-checklist.md +270 -0
- claude_mpm/skills/bundled/testing/test-quality-inspector/references/red-flags.md +436 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +140 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +572 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +411 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +569 -0
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +695 -0
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +184 -0
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +459 -0
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +479 -0
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +687 -0
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +758 -0
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +868 -0
- claude_mpm/skills/skill_manager.py +98 -3
- claude_mpm/templates/.pre-commit-config.yaml +112 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/METADATA +3 -2
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/RECORD +244 -68
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/0.B_FtCwCQ.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/assets/2.Cl_eSA4x.css +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/BgChzWQ1.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/CIXEwuWe.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/chunks/DMkZpdF2.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/app.DTL5mJO-.js +0 -2
- claude_mpm/dashboard/static/svelte-build/_app/immutable/entry/start.DzuEhzqh.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/1.DFLC8jdE.js +0 -1
- claude_mpm/dashboard/static/svelte-build/_app/immutable/nodes/2.DPvEihJJ.js +0 -10
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager.cpython-311.pyc +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/WHEEL +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/entry_points.txt +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/licenses/LICENSE-FAQ.md +0 -0
- {claude_mpm-5.4.36.dist-info → claude_mpm-5.4.62.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,742 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: flexlayout-react
|
|
3
|
+
description: FlexLayout for React - Advanced docking layout manager with drag-and-drop, tabs, splitters, and complex window management
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
category: development
|
|
6
|
+
author: Claude MPM Team
|
|
7
|
+
license: MIT
|
|
8
|
+
progressive_disclosure:
|
|
9
|
+
entry_point:
|
|
10
|
+
summary: "Professional docking layout system: drag-and-drop panels, tabs, splitters, persistence, complex multi-pane interfaces"
|
|
11
|
+
when_to_use: "Building IDE-like interfaces, dashboard builders, multi-document editors, complex admin panels with draggable panes"
|
|
12
|
+
quick_start: "1. Create model with Model.fromJson() 2. Wrap app in Layout component 3. Define factory function 4. Persist with model.toJson()"
|
|
13
|
+
context_limit: 700
|
|
14
|
+
tags:
|
|
15
|
+
- react
|
|
16
|
+
- layout
|
|
17
|
+
- docking
|
|
18
|
+
- drag-drop
|
|
19
|
+
- ide
|
|
20
|
+
- dashboard
|
|
21
|
+
- flexlayout
|
|
22
|
+
requires_tools: []
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# FlexLayout-React - Professional Docking Layouts
|
|
26
|
+
|
|
27
|
+
## Overview
|
|
28
|
+
|
|
29
|
+
FlexLayout-React provides IDE-quality docking layouts with drag-and-drop, tabs, splitters, and complex window management. Perfect for dashboards, IDEs, admin panels, and any interface requiring flexible, user-customizable layouts.
|
|
30
|
+
|
|
31
|
+
**Key Features**:
|
|
32
|
+
- Drag-and-drop panel repositioning
|
|
33
|
+
- Tabbed interfaces with close, maximize, minimize
|
|
34
|
+
- Splitters for resizable panes
|
|
35
|
+
- Border docking areas
|
|
36
|
+
- Layout persistence (save/restore)
|
|
37
|
+
- Programmatic layout control
|
|
38
|
+
- TypeScript support
|
|
39
|
+
|
|
40
|
+
**Installation**:
|
|
41
|
+
```bash
|
|
42
|
+
npm install flexlayout-react
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Basic Setup
|
|
46
|
+
|
|
47
|
+
### 1. Define Layout Model
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { Model, IJsonModel } from 'flexlayout-react';
|
|
51
|
+
|
|
52
|
+
const initialLayout: IJsonModel = {
|
|
53
|
+
global: {
|
|
54
|
+
tabEnableClose: true,
|
|
55
|
+
tabEnableRename: false,
|
|
56
|
+
},
|
|
57
|
+
borders: [],
|
|
58
|
+
layout: {
|
|
59
|
+
type: 'row',
|
|
60
|
+
weight: 100,
|
|
61
|
+
children: [
|
|
62
|
+
{
|
|
63
|
+
type: 'tabset',
|
|
64
|
+
weight: 50,
|
|
65
|
+
children: [
|
|
66
|
+
{
|
|
67
|
+
type: 'tab',
|
|
68
|
+
name: 'Explorer',
|
|
69
|
+
component: 'explorer',
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
type: 'tabset',
|
|
75
|
+
weight: 50,
|
|
76
|
+
children: [
|
|
77
|
+
{
|
|
78
|
+
type: 'tab',
|
|
79
|
+
name: 'Editor',
|
|
80
|
+
component: 'editor',
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Create model
|
|
89
|
+
const model = Model.fromJson(initialLayout);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### 2. Create Layout Component
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import React, { useRef } from 'react';
|
|
96
|
+
import { Layout, Model, TabNode, IJsonTabNode } from 'flexlayout-react';
|
|
97
|
+
import 'flexlayout-react/style/dark.css'; // or light.css
|
|
98
|
+
|
|
99
|
+
interface ComponentRegistry {
|
|
100
|
+
explorer: React.ComponentType;
|
|
101
|
+
editor: React.ComponentType;
|
|
102
|
+
terminal: React.ComponentType;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function App() {
|
|
106
|
+
const modelRef = useRef(Model.fromJson(initialLayout));
|
|
107
|
+
|
|
108
|
+
const factory = (node: TabNode) => {
|
|
109
|
+
const component = node.getComponent();
|
|
110
|
+
|
|
111
|
+
switch (component) {
|
|
112
|
+
case 'explorer':
|
|
113
|
+
return <ExplorerPanel />;
|
|
114
|
+
case 'editor':
|
|
115
|
+
return <EditorPanel />;
|
|
116
|
+
case 'terminal':
|
|
117
|
+
return <TerminalPanel />;
|
|
118
|
+
default:
|
|
119
|
+
return <div>Unknown component: {component}</div>;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<div style={{ width: '100vw', height: '100vh' }}>
|
|
125
|
+
<Layout
|
|
126
|
+
model={modelRef.current}
|
|
127
|
+
factory={factory}
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### 3. Component Implementation
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
function ExplorerPanel() {
|
|
138
|
+
return (
|
|
139
|
+
<div className="panel-explorer">
|
|
140
|
+
<h3>File Explorer</h3>
|
|
141
|
+
<ul>
|
|
142
|
+
<li>src/</li>
|
|
143
|
+
<li>public/</li>
|
|
144
|
+
<li>package.json</li>
|
|
145
|
+
</ul>
|
|
146
|
+
</div>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function EditorPanel() {
|
|
151
|
+
return (
|
|
152
|
+
<div className="panel-editor">
|
|
153
|
+
<textarea
|
|
154
|
+
style={{ width: '100%', height: '100%' }}
|
|
155
|
+
placeholder="Start typing..."
|
|
156
|
+
/>
|
|
157
|
+
</div>
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Advanced Layout Configurations
|
|
163
|
+
|
|
164
|
+
### Complex Multi-Pane Layout
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
const complexLayout: IJsonModel = {
|
|
168
|
+
global: {
|
|
169
|
+
tabEnableClose: true,
|
|
170
|
+
tabEnableRename: false,
|
|
171
|
+
tabEnableDrag: true,
|
|
172
|
+
tabEnableFloat: true,
|
|
173
|
+
borderSize: 200,
|
|
174
|
+
},
|
|
175
|
+
borders: [
|
|
176
|
+
{
|
|
177
|
+
type: 'border',
|
|
178
|
+
location: 'left',
|
|
179
|
+
size: 250,
|
|
180
|
+
children: [
|
|
181
|
+
{
|
|
182
|
+
type: 'tab',
|
|
183
|
+
name: 'Explorer',
|
|
184
|
+
component: 'explorer',
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
type: 'border',
|
|
190
|
+
location: 'bottom',
|
|
191
|
+
size: 200,
|
|
192
|
+
children: [
|
|
193
|
+
{
|
|
194
|
+
type: 'tab',
|
|
195
|
+
name: 'Terminal',
|
|
196
|
+
component: 'terminal',
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
type: 'tab',
|
|
200
|
+
name: 'Output',
|
|
201
|
+
component: 'output',
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}
|
|
205
|
+
],
|
|
206
|
+
layout: {
|
|
207
|
+
type: 'row',
|
|
208
|
+
weight: 100,
|
|
209
|
+
children: [
|
|
210
|
+
{
|
|
211
|
+
type: 'tabset',
|
|
212
|
+
weight: 70,
|
|
213
|
+
children: [
|
|
214
|
+
{
|
|
215
|
+
type: 'tab',
|
|
216
|
+
name: 'Editor 1',
|
|
217
|
+
component: 'editor',
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
type: 'tab',
|
|
221
|
+
name: 'Editor 2',
|
|
222
|
+
component: 'editor',
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
type: 'tabset',
|
|
228
|
+
weight: 30,
|
|
229
|
+
children: [
|
|
230
|
+
{
|
|
231
|
+
type: 'tab',
|
|
232
|
+
name: 'Properties',
|
|
233
|
+
component: 'properties',
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
type: 'tab',
|
|
237
|
+
name: 'Outline',
|
|
238
|
+
component: 'outline',
|
|
239
|
+
}
|
|
240
|
+
]
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Nested Rows and Columns
|
|
248
|
+
|
|
249
|
+
```typescript
|
|
250
|
+
const nestedLayout: IJsonModel = {
|
|
251
|
+
global: {},
|
|
252
|
+
borders: [],
|
|
253
|
+
layout: {
|
|
254
|
+
type: 'row',
|
|
255
|
+
children: [
|
|
256
|
+
{
|
|
257
|
+
type: 'col',
|
|
258
|
+
weight: 50,
|
|
259
|
+
children: [
|
|
260
|
+
{
|
|
261
|
+
type: 'tabset',
|
|
262
|
+
weight: 70,
|
|
263
|
+
children: [
|
|
264
|
+
{ type: 'tab', name: 'Top Left', component: 'panel-a' }
|
|
265
|
+
]
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
type: 'tabset',
|
|
269
|
+
weight: 30,
|
|
270
|
+
children: [
|
|
271
|
+
{ type: 'tab', name: 'Bottom Left', component: 'panel-b' }
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
]
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
type: 'col',
|
|
278
|
+
weight: 50,
|
|
279
|
+
children: [
|
|
280
|
+
{
|
|
281
|
+
type: 'tabset',
|
|
282
|
+
weight: 30,
|
|
283
|
+
children: [
|
|
284
|
+
{ type: 'tab', name: 'Top Right', component: 'panel-c' }
|
|
285
|
+
]
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
type: 'tabset',
|
|
289
|
+
weight: 70,
|
|
290
|
+
children: [
|
|
291
|
+
{ type: 'tab', name: 'Bottom Right', component: 'panel-d' }
|
|
292
|
+
]
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
}
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Layout Persistence
|
|
302
|
+
|
|
303
|
+
### Save and Restore Layout
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
import { useState, useEffect } from 'react';
|
|
307
|
+
import { Model, Actions } from 'flexlayout-react';
|
|
308
|
+
|
|
309
|
+
function LayoutManager() {
|
|
310
|
+
const [model, setModel] = useState(() => {
|
|
311
|
+
// Load from localStorage
|
|
312
|
+
const saved = localStorage.getItem('layout');
|
|
313
|
+
return saved
|
|
314
|
+
? Model.fromJson(JSON.parse(saved))
|
|
315
|
+
: Model.fromJson(defaultLayout);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Save on model change
|
|
319
|
+
const onModelChange = (newModel: Model) => {
|
|
320
|
+
const json = newModel.toJson();
|
|
321
|
+
localStorage.setItem('layout', JSON.stringify(json));
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
return (
|
|
325
|
+
<Layout
|
|
326
|
+
model={model}
|
|
327
|
+
factory={factory}
|
|
328
|
+
onModelChange={onModelChange}
|
|
329
|
+
/>
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### Reset to Default Layout
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
function LayoutControls({ model }: { model: Model }) {
|
|
338
|
+
const resetLayout = () => {
|
|
339
|
+
const newModel = Model.fromJson(defaultLayout);
|
|
340
|
+
// Need to replace model reference
|
|
341
|
+
window.location.reload(); // Simple approach
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const saveLayout = () => {
|
|
345
|
+
const json = model.toJson();
|
|
346
|
+
const blob = new Blob([JSON.stringify(json, null, 2)], {
|
|
347
|
+
type: 'application/json'
|
|
348
|
+
});
|
|
349
|
+
const url = URL.createObjectURL(blob);
|
|
350
|
+
const a = document.createElement('a');
|
|
351
|
+
a.href = url;
|
|
352
|
+
a.download = 'layout.json';
|
|
353
|
+
a.click();
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
return (
|
|
357
|
+
<div className="layout-controls">
|
|
358
|
+
<button onClick={resetLayout}>Reset Layout</button>
|
|
359
|
+
<button onClick={saveLayout}>Export Layout</button>
|
|
360
|
+
</div>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
## Dynamic Tab Management
|
|
366
|
+
|
|
367
|
+
### Adding Tabs Programmatically
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
import { Actions, DockLocation } from 'flexlayout-react';
|
|
371
|
+
|
|
372
|
+
function addNewTab(model: Model, tabsetId: string) {
|
|
373
|
+
model.doAction(Actions.addNode(
|
|
374
|
+
{
|
|
375
|
+
type: 'tab',
|
|
376
|
+
name: `New Tab ${Date.now()}`,
|
|
377
|
+
component: 'editor',
|
|
378
|
+
},
|
|
379
|
+
tabsetId,
|
|
380
|
+
DockLocation.CENTER,
|
|
381
|
+
-1
|
|
382
|
+
));
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Add to specific tabset
|
|
386
|
+
const addToExplorer = () => {
|
|
387
|
+
addNewTab(model, 'explorer-tabset-id');
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// Add to active tabset
|
|
391
|
+
const addToActive = () => {
|
|
392
|
+
const activeTabset = model.getActiveTabset();
|
|
393
|
+
if (activeTabset) {
|
|
394
|
+
addNewTab(model, activeTabset.getId());
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Closing Tabs
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
function closeTab(model: Model, tabId: string) {
|
|
403
|
+
model.doAction(Actions.deleteTab(tabId));
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function closeAllTabs(model: Model) {
|
|
407
|
+
const tabsets = model.getRoot().getChildren();
|
|
408
|
+
tabsets.forEach(tabset => {
|
|
409
|
+
if (tabset.getType() === 'tabset') {
|
|
410
|
+
const tabs = tabset.getChildren();
|
|
411
|
+
tabs.forEach(tab => {
|
|
412
|
+
if (tab.getType() === 'tab') {
|
|
413
|
+
model.doAction(Actions.deleteTab(tab.getId()));
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Tab Context and Props
|
|
422
|
+
|
|
423
|
+
### Passing Data to Components
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
interface EditorTabProps {
|
|
427
|
+
node: TabNode;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function EditorTab({ node }: EditorTabProps) {
|
|
431
|
+
const filepath = node.getConfig()?.filepath as string;
|
|
432
|
+
const readonly = node.getConfig()?.readonly as boolean;
|
|
433
|
+
|
|
434
|
+
return (
|
|
435
|
+
<div>
|
|
436
|
+
<p>Editing: {filepath}</p>
|
|
437
|
+
<textarea readOnly={readonly} />
|
|
438
|
+
</div>
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// Factory with data passing
|
|
443
|
+
const factory = (node: TabNode) => {
|
|
444
|
+
const component = node.getComponent();
|
|
445
|
+
|
|
446
|
+
switch (component) {
|
|
447
|
+
case 'editor':
|
|
448
|
+
return <EditorTab node={node} />;
|
|
449
|
+
default:
|
|
450
|
+
return <div>Unknown</div>;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
// Create tab with config
|
|
455
|
+
const newTab: IJsonTabNode = {
|
|
456
|
+
type: 'tab',
|
|
457
|
+
name: 'my-file.ts',
|
|
458
|
+
component: 'editor',
|
|
459
|
+
config: {
|
|
460
|
+
filepath: '/src/my-file.ts',
|
|
461
|
+
readonly: false,
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
### Accessing Tab State
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
function SmartPanel({ node }: { node: TabNode }) {
|
|
470
|
+
const name = node.getName();
|
|
471
|
+
const isActive = node.isSelected();
|
|
472
|
+
const isVisible = node.isVisible();
|
|
473
|
+
|
|
474
|
+
return (
|
|
475
|
+
<div className={isActive ? 'active' : 'inactive'}>
|
|
476
|
+
<h3>{name}</h3>
|
|
477
|
+
{isVisible && <p>This tab is visible</p>}
|
|
478
|
+
</div>
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
## Styling and Theming
|
|
484
|
+
|
|
485
|
+
### Custom CSS
|
|
486
|
+
|
|
487
|
+
```css
|
|
488
|
+
/* Override FlexLayout styles */
|
|
489
|
+
.flexlayout__layout {
|
|
490
|
+
background: #1e1e1e;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
.flexlayout__tab {
|
|
494
|
+
background: #2d2d2d;
|
|
495
|
+
color: #cccccc;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.flexlayout__tab:hover {
|
|
499
|
+
background: #3e3e3e;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
.flexlayout__tab_button--selected {
|
|
503
|
+
background: #1e1e1e;
|
|
504
|
+
border-bottom: 2px solid #007acc;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
.flexlayout__splitter {
|
|
508
|
+
background: #2d2d2d;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.flexlayout__splitter:hover {
|
|
512
|
+
background: #007acc;
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Dark/Light Theme Toggle
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
import 'flexlayout-react/style/dark.css';
|
|
520
|
+
// or
|
|
521
|
+
import 'flexlayout-react/style/light.css';
|
|
522
|
+
|
|
523
|
+
function ThemeToggle() {
|
|
524
|
+
const [theme, setTheme] = useState<'dark' | 'light'>('dark');
|
|
525
|
+
|
|
526
|
+
useEffect(() => {
|
|
527
|
+
// Dynamically load theme
|
|
528
|
+
const link = document.createElement('link');
|
|
529
|
+
link.rel = 'stylesheet';
|
|
530
|
+
link.href = `flexlayout-react/style/${theme}.css`;
|
|
531
|
+
document.head.appendChild(link);
|
|
532
|
+
|
|
533
|
+
return () => {
|
|
534
|
+
document.head.removeChild(link);
|
|
535
|
+
};
|
|
536
|
+
}, [theme]);
|
|
537
|
+
|
|
538
|
+
return (
|
|
539
|
+
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
|
|
540
|
+
Toggle Theme
|
|
541
|
+
</button>
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
## Integration with Tauri
|
|
547
|
+
|
|
548
|
+
### Persisting Layout to Tauri Backend
|
|
549
|
+
|
|
550
|
+
```typescript
|
|
551
|
+
import { invoke } from '@tauri-apps/api/core';
|
|
552
|
+
|
|
553
|
+
async function saveLayoutToTauri(model: Model) {
|
|
554
|
+
const json = model.toJson();
|
|
555
|
+
await invoke('save_layout', {
|
|
556
|
+
layout: JSON.stringify(json)
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
async function loadLayoutFromTauri(): Promise<Model> {
|
|
561
|
+
const layout = await invoke<string>('load_layout');
|
|
562
|
+
return Model.fromJson(JSON.parse(layout));
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// Tauri command (Rust)
|
|
566
|
+
// #[tauri::command]
|
|
567
|
+
// async fn save_layout(layout: String) -> Result<(), String> {
|
|
568
|
+
// let app_dir = app.path_resolver().app_data_dir()?;
|
|
569
|
+
// let layout_file = app_dir.join("layout.json");
|
|
570
|
+
// tokio::fs::write(layout_file, layout).await?;
|
|
571
|
+
// Ok(())
|
|
572
|
+
// }
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Window-Specific Layouts
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
import { invoke } from '@tauri-apps/api/core';
|
|
579
|
+
import { getCurrent } from '@tauri-apps/api/window';
|
|
580
|
+
|
|
581
|
+
function WindowLayout() {
|
|
582
|
+
const [model, setModel] = useState<Model | null>(null);
|
|
583
|
+
|
|
584
|
+
useEffect(() => {
|
|
585
|
+
const currentWindow = getCurrent();
|
|
586
|
+
const windowLabel = currentWindow.label;
|
|
587
|
+
|
|
588
|
+
// Load layout for this specific window
|
|
589
|
+
invoke<string>('load_window_layout', { windowLabel })
|
|
590
|
+
.then(layout => {
|
|
591
|
+
setModel(Model.fromJson(JSON.parse(layout)));
|
|
592
|
+
})
|
|
593
|
+
.catch(() => {
|
|
594
|
+
setModel(Model.fromJson(defaultLayout));
|
|
595
|
+
});
|
|
596
|
+
}, []);
|
|
597
|
+
|
|
598
|
+
const onModelChange = (newModel: Model) => {
|
|
599
|
+
const currentWindow = getCurrent();
|
|
600
|
+
const json = newModel.toJson();
|
|
601
|
+
|
|
602
|
+
invoke('save_window_layout', {
|
|
603
|
+
windowLabel: currentWindow.label,
|
|
604
|
+
layout: JSON.stringify(json)
|
|
605
|
+
});
|
|
606
|
+
};
|
|
607
|
+
|
|
608
|
+
if (!model) return <div>Loading...</div>;
|
|
609
|
+
|
|
610
|
+
return (
|
|
611
|
+
<Layout
|
|
612
|
+
model={model}
|
|
613
|
+
factory={factory}
|
|
614
|
+
onModelChange={onModelChange}
|
|
615
|
+
/>
|
|
616
|
+
);
|
|
617
|
+
}
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
## Advanced Patterns
|
|
621
|
+
|
|
622
|
+
### Custom Tab Headers
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
import { Layout, Model, TabNode, ITabRenderValues } from 'flexlayout-react';
|
|
626
|
+
|
|
627
|
+
function App() {
|
|
628
|
+
const onRenderTab = (
|
|
629
|
+
node: TabNode,
|
|
630
|
+
renderValues: ITabRenderValues
|
|
631
|
+
) => {
|
|
632
|
+
const modified = node.getConfig()?.modified as boolean;
|
|
633
|
+
|
|
634
|
+
renderValues.content = (
|
|
635
|
+
<div className="custom-tab-header">
|
|
636
|
+
<span>{node.getName()}</span>
|
|
637
|
+
{modified && <span className="modified-indicator">●</span>}
|
|
638
|
+
</div>
|
|
639
|
+
);
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
return (
|
|
643
|
+
<Layout
|
|
644
|
+
model={model}
|
|
645
|
+
factory={factory}
|
|
646
|
+
onRenderTab={onRenderTab}
|
|
647
|
+
/>
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
### Tab Actions (Custom Buttons)
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
const onRenderTab = (node: TabNode, renderValues: ITabRenderValues) => {
|
|
656
|
+
renderValues.buttons.push(
|
|
657
|
+
<button
|
|
658
|
+
key="save"
|
|
659
|
+
onClick={() => saveTabContent(node)}
|
|
660
|
+
title="Save"
|
|
661
|
+
>
|
|
662
|
+
💾
|
|
663
|
+
</button>
|
|
664
|
+
);
|
|
665
|
+
|
|
666
|
+
renderValues.buttons.push(
|
|
667
|
+
<button
|
|
668
|
+
key="duplicate"
|
|
669
|
+
onClick={() => duplicateTab(node)}
|
|
670
|
+
title="Duplicate"
|
|
671
|
+
>
|
|
672
|
+
📋
|
|
673
|
+
</button>
|
|
674
|
+
);
|
|
675
|
+
};
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
## Best Practices
|
|
679
|
+
|
|
680
|
+
1. **Persist layouts** - Save to localStorage or backend for user experience
|
|
681
|
+
2. **Use unique component names** - Avoid collisions in factory function
|
|
682
|
+
3. **Handle missing components** - Factory should have default case
|
|
683
|
+
4. **Memoize factory function** - Prevent unnecessary re-renders
|
|
684
|
+
5. **Use config for tab data** - Store tab-specific props in config
|
|
685
|
+
6. **Provide reset mechanism** - Users can restore default layout
|
|
686
|
+
7. **Test layout changes** - Verify persistence works correctly
|
|
687
|
+
8. **Handle edge cases** - Empty tabsets, deleted components
|
|
688
|
+
9. **Use borders wisely** - Left/right/top/bottom for tools, main area for content
|
|
689
|
+
10. **Optimize large layouts** - Lazy-load components when possible
|
|
690
|
+
|
|
691
|
+
## Common Pitfalls
|
|
692
|
+
|
|
693
|
+
❌ **Not memoizing model**:
|
|
694
|
+
```typescript
|
|
695
|
+
// WRONG - creates new model on every render
|
|
696
|
+
function App() {
|
|
697
|
+
const model = Model.fromJson(layout); // Bad!
|
|
698
|
+
return <Layout model={model} />;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// CORRECT
|
|
702
|
+
function App() {
|
|
703
|
+
const modelRef = useRef(Model.fromJson(layout));
|
|
704
|
+
return <Layout model={modelRef.current} />;
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
❌ **Forgetting CSS import**:
|
|
709
|
+
```typescript
|
|
710
|
+
// WRONG - layout won't display correctly
|
|
711
|
+
import { Layout } from 'flexlayout-react';
|
|
712
|
+
// Missing: import 'flexlayout-react/style/dark.css';
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
❌ **Not handling onModelChange**:
|
|
716
|
+
```typescript
|
|
717
|
+
// WRONG - layout changes not persisted
|
|
718
|
+
<Layout model={model} factory={factory} />
|
|
719
|
+
|
|
720
|
+
// CORRECT
|
|
721
|
+
<Layout
|
|
722
|
+
model={model}
|
|
723
|
+
factory={factory}
|
|
724
|
+
onModelChange={saveLayout}
|
|
725
|
+
/>
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
## Resources
|
|
729
|
+
|
|
730
|
+
- **Documentation**: https://github.com/caplin/FlexLayout
|
|
731
|
+
- **Examples**: https://rawgit.com/caplin/FlexLayout/demos/demos/index.html
|
|
732
|
+
- **TypeScript Types**: Included in package
|
|
733
|
+
|
|
734
|
+
## Summary
|
|
735
|
+
|
|
736
|
+
- **FlexLayout** provides IDE-quality docking layouts
|
|
737
|
+
- **Model-driven** - Define layout as JSON, control programmatically
|
|
738
|
+
- **Persistent** - Save/restore user layouts easily
|
|
739
|
+
- **Customizable** - Custom tabs, borders, themes
|
|
740
|
+
- **React-friendly** - Hooks, TypeScript support
|
|
741
|
+
- **Perfect for** - IDEs, dashboards, admin panels, complex UIs
|
|
742
|
+
- **Tauri integration** - Persist to backend, window-specific layouts
|