Skip to content

Commit c15bb0e

Browse files
committed
feat(crafting): add PRD
1 parent 4b66e09 commit c15bb0e

File tree

11 files changed

+466
-2
lines changed

11 files changed

+466
-2
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ mendixProject
2626
tests
2727
.turbo
2828
automation/run-e2e/ctrf/*.json
29+
.cursor
30+
.windsurf
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env ts-node-script
2+
3+
import { mkdir, readdir, lstat, symlink, unlink } from "fs/promises";
4+
import path from "node:path";
5+
6+
async function ensureSymlink(targetRel: string, linkPath: string): Promise<void> {
7+
try {
8+
const stat = await lstat(linkPath).catch(() => null);
9+
if (stat) {
10+
await unlink(linkPath);
11+
}
12+
await symlink(targetRel, linkPath);
13+
} catch (err) {
14+
console.error(`Failed to create symlink for ${linkPath}:`, err);
15+
}
16+
}
17+
18+
async function main(): Promise<void> {
19+
const repoRoot = path.resolve(process.cwd(), "../..");
20+
const SRC_DIR = path.join(repoRoot, "docs", "requirements");
21+
const CURSOR_DIR = path.join(repoRoot, ".cursor", "rules");
22+
const WINDSURF_DIR = path.join(repoRoot, ".windsurf", "rules");
23+
24+
// Ensure target directories exist
25+
await Promise.all([mkdir(CURSOR_DIR, { recursive: true }), mkdir(WINDSURF_DIR, { recursive: true })]);
26+
27+
const files = (await readdir(SRC_DIR)).filter(f => f.endsWith(".md"));
28+
29+
await Promise.all(
30+
files.map(async file => {
31+
const base = path.basename(file, ".md");
32+
const srcAbsolute = path.join(SRC_DIR, file);
33+
34+
const cursorLink = path.join(CURSOR_DIR, `${base}.mdc`);
35+
const windsurfLink = path.join(WINDSURF_DIR, `${base}.md`);
36+
37+
const relFromCursor = path.relative(path.dirname(cursorLink), srcAbsolute);
38+
const relFromWindsurf = path.relative(path.dirname(windsurfLink), srcAbsolute);
39+
40+
await Promise.all([ensureSymlink(relFromCursor, cursorLink), ensureSymlink(relFromWindsurf, windsurfLink)]);
41+
})
42+
);
43+
44+
console.log("Agent rules links updated.");
45+
}
46+
47+
main().catch(err => {
48+
console.error(err);
49+
process.exit(1);
50+
});

automation/utils/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"copyright": "© Mendix Technology BV 2025. All rights reserved.",
66
"private": true,
77
"bin": {
8+
"rui-agent-rules": "bin/rui-agent-rules.ts",
89
"rui-create-gh-release": "bin/rui-create-gh-release.ts",
910
"rui-create-translation": "bin/rui-create-translation.ts",
1011
"rui-publish-marketplace": "bin/rui-publish-marketplace.ts",
@@ -21,6 +22,7 @@
2122
"tsconfig.json"
2223
],
2324
"scripts": {
25+
"agent-rules": "ts-node bin/rui-agent-rules.ts",
2426
"changelog": "ts-node bin/rui-changelog-helper.ts",
2527
"compile:parser:module": "peggy -o ./src/changelog-parser/parser/widget/widget.js ./src/changelog-parser/parser/widget/widget.pegjs",
2628
"compile:parser:widget": "peggy -o ./src/changelog-parser/parser/module/module.js ./src/changelog-parser/parser/module/module.pegjs",

docs/requirements/app-flow.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
6+
7+
# Pluggable Widget Lifecycle & Application Flow
8+
9+
Understanding how a pluggable widget moves from development to usage in Mendix Studio Pro is essential. This document breaks down the flow of creating, registering, configuring, building, and integrating a widget into Mendix Studio Pro.
10+
11+
## 1. Scaffold / Creation of a New Widget
12+
13+
Developers typically scaffold a new widget using the Mendix Pluggable Widget Generator. This generator creates:
14+
15+
- A package structure (e.g., `packages/pluggableWidgets/my-widget-web/`).
16+
- Initial files: a TypeScript/TSX file for the React component, a corresponding XML configuration file, a README, and build configuration files.
17+
18+
Using the generator ensures correct conventions in folder layout, naming, and sample code.
19+
20+
## 2. Widget Registration via XML
21+
22+
Every widget has an XML file (e.g., `MyWidget.xml`) that:
23+
24+
- Defines a unique widget ID and name (following the namespace pattern).
25+
- Specifies metadata for categorization in Studio Pro.
26+
- Defines properties (inputs, outputs, events) including types and defaults.
27+
- Includes system properties (e.g., Visibility, Tab index).
28+
29+
Studio Pro reads this XML to register the widget. Errors in the XML (such as duplicate IDs) prevent proper registration.
30+
31+
## 3. Development: Implementing and Configuring the Widget
32+
33+
After scaffolding and XML configuration:
34+
35+
- **Coding:** Implement the widget's functionality in a `.tsx` file using React. The component receives props corresponding to the XML-defined properties.
36+
- **Styling:** Use appropriate CSS classes (preferably Atlas UI classes) rather than inline styles.
37+
- **Configuration:** Test the widget by adding it to a page in Studio Pro and verifying that properties appear and function as defined.
38+
39+
Live reload is used during development to quickly reflect changes.
40+
41+
## 4. Build and Bundle
42+
43+
Using pnpm (or npm), developers:
44+
45+
- Run `pnpm install` to install dependencies.
46+
- Set the `MX_PROJECT_PATH` to point to a Mendix test project.
47+
- You can ask the name of the project, and then set `MX_PROJECT_PATH` dynamically, for example: `export MX_PROJECT_PATH="$HOME/Mendix/${PROJECT_NAME}"`. This way, whether you run `pnpm start` or `pnpm build`, the output is deployed to the correct Studio Pro project and we can immediately see the latest changes.
48+
- Run `pnpm start` to build the widget using Rollup (compiling TypeScript and SCSS). The output is placed in the Mendix project's widget folder.
49+
50+
Rollup handles bundling into an optimized, single JavaScript file.
51+
52+
## 5. Integration into Mendix Studio Pro
53+
54+
Once built:
55+
56+
- **During Development:** The widget appears in Studio Pro's toolbox after synchronization. Developers can drag it onto pages and configure its properties.
57+
- **Packaging:** For distribution, a production build generates an MPK (a ZIP package) that can be imported into any Mendix project.
58+
- **At Runtime:** The Mendix Client instantiates the widget, passes the configured properties (as EditableValue, DynamicValue, ActionValue, etc.), and the widget renders its UI.
59+
60+
## 6. Summary of the Flow
61+
62+
1. **Design/Develop:** Write widget code and define properties in XML.
63+
2. **Register:** XML registration makes the widget available in Studio Pro.
64+
3. **Configure in App:** Drag the widget onto a page and set its properties.
65+
4. **Build:** Compile using pnpm/Rollup.
66+
5. **Run/Integrate:** Mendix client loads the widget with runtime data.
67+
6. **Iteration:** Repeat as needed with live reload and synchronization.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
6+
7+
# Widget Data Flow & Backend Integration
8+
9+
Although pluggable widgets are primarily client-side components, they operate within the Mendix ecosystem. This document explains how data flows between a widget and the Mendix runtime, and how events are handled.
10+
11+
## Widget XML Configuration and Mendix Runtime
12+
13+
- **Property Types and Mendix Data:**
14+
- **attribute:** Provided as an EditableValue object.
15+
- **textTemplate:** Passed as a DynamicValue<string>.
16+
- **objects/object:** Provided as a ListValue or ObjectValue.
17+
- **Simple types:** Passed as plain JS values.
18+
- **action:** Provided as an ActionValue with methods like `execute()`.
19+
- **Data Context:** Widgets may require a context object if placed within a Data View.
20+
- **Offline Capable:** XML can mark widgets as offline capable, meaning they are designed to work without a network connection.
21+
22+
## Data Flow: Reading and Updating Data
23+
24+
- **Initial Data Loading:** On page load, Mendix supplies data via props (e.g., EditableValue, DynamicValue). Widgets should render loading states if data is not yet available.
25+
- **Two-Way Data Binding:** For interactive widgets, changes are pushed back using methods like `EditableValue.setValue()`.
26+
- **Events and Actions:** User-triggered events call ActionValue's `execute()` method (after checking `canExecute`) to run Mendix microflows or nanoflows.
27+
28+
## Mendix Client and Widget Lifecycle
29+
30+
- **Instantiation:** Mendix creates the widget component on page load and passes the required props.
31+
- **Re-rendering:** Changes in Mendix data trigger re-rendering via updated props.
32+
- **Destruction:** Widgets unmount when removed; cleanup (e.g., event listeners) should occur during unmount.
33+
- **Communication with the Server:** Widgets trigger server-side logic indirectly via microflows or nanoflows, using data source properties when needed.
34+
35+
## Example: DataGrid2 Interaction
36+
37+
- A DataGrid widget receives a ListValue for data.
38+
- Sorting or row click events trigger ActionValues that may call microflows.
39+
- Updates to the data source result in re-rendering of the widget.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
6+
7+
# Frontend Guidelines for Mendix Pluggable Widgets
8+
9+
This guide provides best practices for front-end development in Mendix pluggable widgets, focusing on styling, component structure, naming, and Atlas design system usage. The goal is to ensure consistent, maintainable widget development.
10+
11+
## CSS and SCSS Styling Guidelines
12+
13+
- **Use SCSS for Styles:** Write all widget styles in SCSS files to leverage variables, mixins, and integration with the overall theme.
14+
- **No Inline Styles for Static Design:** Avoid using inline styles. Instead, assign CSS classes defined in SCSS or use Atlas classes.
15+
- **Leverage Atlas UI Classes:** Utilize predefined Atlas classes (e.g., `btn`, `badge`) to ensure a consistent look.
16+
- **Scoped vs Global Styles:** Prefix custom classes with the widget name (e.g., `.widget-combobox`) to avoid conflicts.
17+
- **Responsive Design:** Use relative units and media queries to ensure the widget adapts gracefully to different screen sizes.
18+
- **Avoid Deep Nesting:** Write clear, maintainable CSS without over-nesting or using `!important` unless absolutely necessary.
19+
- **Design Properties and Conditional Classes:** Implement design properties via toggling classes based on user selections in Studio Pro.
20+
21+
## Naming Conventions (Files, Classes, and Components)
22+
23+
- **Component and File Names:** Use PascalCase for React component files (e.g., `ProgressBar.tsx`).
24+
- **Widget Folder Naming:** Use lowercase names with hyphens ending with "web" (e.g., `badge-button-web`).
25+
- **XML Keys and Attribute Names:** Use lowerCamelCase for XML property keys.
26+
- **CSS Class Naming:** Follow a BEM-like convention for custom classes to maintain structure and clarity.
27+
28+
## Component Best Practices
29+
30+
- **Mendix Data API Usage:** Use Mendix API objects (EditableValue, ActionValue, etc.) correctly, checking conditions such as `canExecute` before calling actions.
31+
- **State Management:** Use React state for UI-specific state and rely on Mendix props for persistent data. There are usages of Context and State management tools(mobx)
32+
- **Performance Considerations:** Optimize renders, avoid heavy computations, and consider memoization.
33+
- **Clean Up:** Ensure any event listeners or timers are cleaned up appropriately.
34+
- **No Direct DOM Manipulation:** Use React's state and props to drive UI changes rather than direct DOM queries.
35+
- **Accessibility:** Use semantic HTML, proper ARIA attributes, and ensure keyboard navigation is supported.
36+
37+
## Using Atlas UI and Theming
38+
39+
- **Consistent Look and Feel:** Ensure widgets integrate with Atlas UI by using default Atlas classes for common elements.
40+
- **Custom Themes Support:** Build widgets so that they naturally adopt custom Atlas themes without hard-coded values.
41+
- **Layout and Sizing:** Use flexible layouts (e.g., percentage widths, flexbox) that adapt to container sizes.
42+
- **No Overriding Atlas Core Classes:** Do not override core Atlas classes; wrap widget elements if custom styling is needed.
43+
- **Example – Consistent Button:** Use `<button class="btn btn-secondary" type="button">Click</button>` instead of custom-styled divs.
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
---
2+
description:
3+
globs:
4+
alwaysApply: true
5+
---
6+
7+
# Implementation Plan for a New Pluggable Widget
8+
9+
This document outlines a step-by-step plan to design, build, test, and integrate a new pluggable widget in Mendix.
10+
11+
## 1. Planning and Requirements
12+
13+
- **Define the Widget's Purpose:** Clearly state what the widget does, its name (e.g., "ProgressCircle"), its category, target data, and required properties (e.g., value, maximum, showLabel, onClick).
14+
- **Check Existing Patterns:** Review similar widgets for best practices and to avoid duplicating functionality.
15+
16+
## 2. Environment Setup
17+
18+
- **Prerequisites:** Install Node.js (using the version specified in the repository), Mendix Studio Pro.
19+
- **Folder Structure:** Create a new package under `packages/pluggableWidgets/` in the monorepo or use a standalone directory.
20+
21+
4. Define Widget Properties in XML
22+
Edit the generated XML file (e.g., ProgressCircle.xml) to define properties and property groups.
23+
24+
Ensure property keys match the TypeScript props.
25+
26+
Do not change the widget's unique ID unless necessary.
27+
28+
5. Implement the React Component
29+
Modify the generated .tsx file to match the XML-defined properties.
30+
31+
Use Mendix API types (e.g., EditableValue, DynamicValue, ActionValue) correctly.
32+
33+
Implement basic rendering and add error/loading states.
34+
35+
Import SCSS for styling and use Atlas UI classes.
36+
37+
6. Build and Run in Studio Pro
38+
Set the MX_PROJECT_PATH environment variable to your test project's directory, you can ask what the project name running in Studio Pro is so that we can se the MX_PROJECT_PATH. The path is: /Users/rahman.unver/Mendix/ProjectName, this path is always same for the macOS version of Studio Pro. For Windows version, our path is /Volumes/[C] Windows11/Users/Rahman.Unver/Documents/ProjectName. example setting:
39+
Windows:
40+
41+
- export MX_PROJECT_PATH=/Volumes/[C] Windows11/Users/Rahman.Unver/Documents/DocumentViewerWidget
42+
- export MX_PROJECT_PATH=/Users/rahman.unver/Mendix/RichTextTest
43+
44+
Run pnpm start (or npm start) to build and watch for changes.
45+
46+
In Studio Pro, synchronize the app directory to load the widget.
47+
48+
Place the widget on a test page and configure properties.
49+
50+
7. Iterative Development
51+
Develop and test iteratively.
52+
53+
Use browser developer tools for debugging.
54+
55+
Adjust XML and TS code as needed when adding new properties or handling edge cases.
56+
57+
8. Testing and Validation
58+
Write unit tests for critical logic using Jest, React Testing Library mainly.
59+
60+
Perform UI/functional testing within a Mendix project.
61+
62+
Test responsiveness, performance, and edge cases.
63+
64+
9. Documentation and Metadata
65+
Update the widget's README with usage instructions and limitations.
66+
67+
Ensure XML descriptions and property captions are clear.
68+
69+
Optionally, add an icon for the widget.
70+
71+
10. Packaging and Sharing
72+
Run npm run build to produce an MPK file.
73+
74+
Test the MPK in a fresh Mendix project.
75+
76+
Update version numbers and changelogs before distribution.
77+
78+
Common Gotchas:
79+
80+
Ensure XML and TypeScript props match exactly.
81+
82+
Install all third-party dependencies.
83+
84+
Maintain case sensitivity in IDs and keys.
85+
86+
Clean up event listeners to avoid memory leaks.
87+
88+
Ensure compatibility with the target Mendix version.
89+
90+
### Github PR Template
91+
92+
<!------STARTS HERE----->
93+
<!--
94+
IMPORTANT: Please read and follow instructions below on how to
95+
open and submit your pull request.
96+
97+
REQUIRED STEPS:
98+
1. Specify correct pull request type.
99+
2. Write meaningful description.
100+
3. Run `pnpm lint` and `pnpm test` in packages you changed and make sure they have no errors.
101+
4. Add new tests (if needed) to cover new functionality.
102+
5. Read checklist below.
103+
104+
CHECKLIST:
105+
- Do you have a JIRA story for your pull request?
106+
- If yes, please format the PR title to match the `[XX-000]: description` pattern.
107+
- If no, please write your PR title using conventional commit rules.
108+
- Does your change require a new version of the widget/module?
109+
- If yes, run `pnpm -w changelog` or update the `CHANGELOG.md` and bump the version manually.
110+
- If no, ignore.
111+
- Do you have related PRs in other Mendix repositories?
112+
- If yes, please link all related pull requests in the description.
113+
- If no, ignore.
114+
- Does your change touch XML, or is it a new feature or behavior?
115+
- If yes, if necessary, please create a PR with updates in the documentation (https://github.com/mendix/docs).
116+
- If no, ignore.
117+
- Is your change a bug fix or a new feature?
118+
- If yes, please add a description (last section in the template) of what should be tested and what steps are needed to test it.
119+
- If no, ignore.
120+
-->
121+
122+
<!--
123+
What type of changes does your PR introduce?
124+
Uncomment relevant sections below by removing `<!--` at the beginning of the line.
125+
-->
126+
127+
### Pull request type
128+
129+
<!-- No code changes (changes to documentation, CI, metadata, etc.)
130+
<!---->
131+
132+
<!-- Dependency changes (any modification to dependencies in `package.json`)
133+
<!---->
134+
135+
<!-- Refactoring (e.g. file rename, variable rename, etc.)
136+
<!---->
137+
138+
<!-- Bug fix (non-breaking change which fixes an issue)
139+
<!---->
140+
141+
<!-- New feature (non-breaking change which adds functionality)
142+
<!---->
143+
144+
<!-- Breaking change (fix or feature that would cause existing functionality to change)
145+
<!---->
146+
147+
<!-- Test related change (New E2E test, test automation, etc.)
148+
<!---->
149+
150+
---
151+
152+
<!---
153+
Describe your changes in detail.
154+
Try to explain WHAT and WHY you change, fix or refactor.
155+
-->
156+
157+
### Description
158+
159+
<!--
160+
Please uncomment and fill in the following section
161+
to describe which part of the package needs to be tested
162+
and how it can be tested.
163+
-->
164+
<!--
165+
### What should be covered while testing?
166+
-->
167+
168+
<!------ENDS HERE----->
169+
170+
Keep this template in mind if I ever ask you to open a PR through command console, Github CLI or similar.

0 commit comments

Comments
 (0)