create-mendix-widget-gleam 2.0.3 → 2.0.4

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.
package/README.md CHANGED
@@ -30,7 +30,7 @@ my-widget/
30
30
  widgets/ # .mpk 위젯 파일 (glendix/widget로 바인딩)
31
31
  bindings.json # 외부 React 컴포넌트 바인딩 설정
32
32
  package.json # npm 의존성 (React, 외부 라이브러리 등)
33
- gleam.toml # Gleam 프로젝트 설정 (glendix >= 2.0.3 의존성 포함)
33
+ gleam.toml # Gleam 프로젝트 설정 (glendix >= 2.0.4 의존성 포함)
34
34
  CLAUDE.md # AI 어시스턴트용 프로젝트 컨텍스트
35
35
  ```
36
36
 
@@ -43,6 +43,7 @@ cd my-widget
43
43
  gleam run -m glendix/install # 의존성 설치
44
44
  gleam run -m glendix/dev # 개발 서버 시작
45
45
  gleam run -m glendix/build # 프로덕션 빌드 (.mpk 생성)
46
+ gleam run -m glendix/marketplace # Marketplace 위젯 검색/다운로드
46
47
  ```
47
48
 
48
49
  ## glendix — React + Mendix 바인딩
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mendix-widget-gleam",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "Scaffold a Mendix Pluggable Widget powered by Gleam",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
package/src/index.mjs CHANGED
@@ -154,8 +154,9 @@ ${GREEN}${BOLD}프로젝트가 생성되었습니다!${RESET}
154
154
  ${BOLD}다음 단계:${RESET}
155
155
 
156
156
  ${CYAN}cd ${names.kebabCase}${RESET}
157
- ${CYAN}gleam run -m glendix/dev${RESET} ${DIM}# 개발 서버 시작${RESET}
158
- ${CYAN}gleam run -m glendix/build${RESET} ${DIM}# 프로덕션 빌드${RESET}
157
+ ${CYAN}gleam run -m glendix/dev${RESET} ${DIM}# 개발 서버 시작${RESET}
158
+ ${CYAN}gleam run -m glendix/build${RESET} ${DIM}# 프로덕션 빌드${RESET}
159
+ ${CYAN}gleam run -m glendix/marketplace${RESET} ${DIM}# Marketplace 위젯 다운로드${RESET}
159
160
  `);
160
161
  }
161
162
 
@@ -225,6 +226,7 @@ gleam run -m glendix/start # Mendix 테스트 프로젝트와 연동 개발
225
226
  gleam run -m glendix/lint # ESLint 실행
226
227
  gleam run -m glendix/lint_fix # ESLint 자동 수정
227
228
  gleam run -m glendix/release # 릴리즈 빌드
229
+ gleam run -m glendix/marketplace # Mendix Marketplace 위젯 검색/다운로드
228
230
  gleam build --target javascript # Gleam → JS 컴파일만
229
231
  gleam test # Gleam 테스트 실행
230
232
  gleam format # Gleam 코드 포맷팅
@@ -237,6 +239,7 @@ gleam format # Gleam 코드 포맷팅
237
239
  - 핵심 개념: opaque 타입, undefined ↔ Option 변환, Attribute 리스트 API
238
240
  - React 바인딩: 엘리먼트 생성, Attribute 리스트, HTML 태그 함수, Hooks, 이벤트 처리, 조건부/리스트 렌더링, 스타일, 외부 React 컴포넌트 바인딩, .mpk 위젯 바인딩
239
241
  - Mendix 바인딩: Props 접근, ValueStatus, EditableValue, ActionValue, DynamicValue, ListValue, ListAttribute, Selection, Reference, Filter, JsDate, Big 등
242
+ - Marketplace 연동: Mendix Marketplace에서 위젯 검색/다운로드 (\`glendix/marketplace\`)
240
243
  - 실전 패턴: 폼 입력 위젯, 데이터 테이블, 검색 가능 리스트, 컴포넌트 합성
241
244
  - 트러블슈팅
242
245
 
@@ -252,6 +255,7 @@ React:
252
255
  - \`glendix/react/svg_attribute\` — 97+ SVG 전용 속성 함수
253
256
  - \`glendix/binding\` — 외부 React 컴포넌트 바인딩
254
257
  - \`glendix/widget\` — .mpk 위젯 컴포넌트 바인딩
258
+ - \`glendix/marketplace\` — Mendix Marketplace 위젯 검색/다운로드
255
259
 
256
260
  Mendix:
257
261
  - \`glendix/mendix\` — \`ValueStatus\`, \`ObjectItem\`, Props 접근자
@@ -368,6 +372,7 @@ gleam run -m glendix/start # Mendix 테스트 프로젝트 연동
368
372
  gleam run -m glendix/lint # ESLint 실행
369
373
  gleam run -m glendix/lint_fix # ESLint 자동 수정
370
374
  gleam run -m glendix/release # 릴리즈 빌드
375
+ gleam run -m glendix/marketplace # Marketplace 위젯 검색/다운로드
371
376
  gleam build --target javascript # Gleam → JS 컴파일만
372
377
  gleam test # 테스트 실행
373
378
  gleam format # 코드 포맷팅
@@ -440,6 +445,28 @@ pub fn tooltip(attrs: List(Attribute)) -> ReactElement {
440
445
 
441
446
  \`html.div\`와 동일한 호출 패턴으로 외부 React 컴포넌트를 사용할 수 있다.
442
447
 
448
+ ## Mendix Marketplace 위젯 다운로드
449
+
450
+ Mendix Marketplace에서 위젯(.mpk)을 인터랙티브하게 검색하고 다운로드할 수 있다. 다운로드 완료 후 바인딩 \`.gleam\` 파일이 자동 생성되어 바로 사용 가능하다.
451
+
452
+ ### 사전 준비
453
+
454
+ \`.env\` 파일에 Mendix Personal Access Token을 설정한다:
455
+
456
+ \`\`\`
457
+ MENDIX_PAT=your_personal_access_token
458
+ \`\`\`
459
+
460
+ > PAT는 [Mendix Developer Settings](https://user-settings.mendix.com/link/developersettings)에서 **Personal Access Tokens** 섹션의 **New Token**을 클릭하여 발급. 필요한 scope: \`mx:marketplace-content:read\`
461
+
462
+ ### 실행
463
+
464
+ \`\`\`bash
465
+ gleam run -m glendix/marketplace
466
+ \`\`\`
467
+
468
+ 인터랙티브 TUI에서 위젯을 검색/선택하면 \`widgets/\` 디렉토리에 \`.mpk\`가 다운로드되고, \`src/widgets/\`에 바인딩 \`.gleam\` 파일이 자동 생성된다.
469
+
443
470
  ## .mpk 위젯 컴포넌트 사용
444
471
 
445
472
  \`widgets/\` 디렉토리에 \`.mpk\` 파일(Mendix 위젯 빌드 결과물)을 배치하면, 다른 위젯 안에서 기존 Mendix 위젯을 React 컴포넌트로 렌더링할 수 있다.
package/template/.env ADDED
@@ -0,0 +1 @@
1
+ MENDIX_PAT=your_personal_access_token
@@ -344,48 +344,47 @@ my_widget/
344
344
 
345
345
  install 시 두 가지가 자동 수행됩니다:
346
346
  - `.mpk` 내부의 `.mjs`와 `.css`가 추출되고, `widget_ffi.mjs`가 생성됩니다
347
- - `.mpk` XML의 `<property>` 정의를 파싱하여 `src/widgets/`에 바인딩 `.gleam` 파일이 자동 생성됩니다 (이미 존재하면 건너뜀)
347
+ - `.mpk` XML의 `<property>` 정의가 부모 위젯 XML(`src/{WidgetName}.xml`)에 `<propertyGroup caption="{위젯명}">` 으로 자동 주입됩니다 (동일 caption이 이미 있으면 건너뜀)
348
348
 
349
- 예를 들어 `Switch.mpk`를 설치하면, `src/widgets/switch.gleam`이 자동 생성됩니다:
349
+ 예를 들어 `Switch.mpk`를 설치하면, 부모 위젯 XML에 다음이 자동 추가됩니다:
350
350
 
351
- ```gleam
352
- // src/widgets/switch.gleam (자동 생성)
353
- import glendix/mendix
354
- import glendix/react.{type JsProps, type ReactElement}
355
- import glendix/react/attribute
356
- import glendix/widget
357
-
358
- /// Switch 위젯 렌더링 - props에서 속성을 읽어 위젯에 전달
359
- pub fn render(props: JsProps) -> ReactElement {
360
- let boolean_attribute = mendix.get_prop_required(props, "booleanAttribute")
361
- let action = mendix.get_prop_required(props, "action")
362
-
363
- let comp = widget.component("Switch")
364
- react.component_el(
365
- comp,
366
- [
367
- attribute.attribute("booleanAttribute", boolean_attribute),
368
- attribute.attribute("action", action),
369
- ],
370
- [],
371
- )
372
- }
351
+ ```xml
352
+ <propertyGroup caption="Switch">
353
+ <property key="booleanAttribute" type="attribute">
354
+ <caption>Boolean attribute</caption>
355
+ <description>Attribute to toggle</description>
356
+ <attributeTypes>
357
+ <attributeType name="Boolean" />
358
+ </attributeTypes>
359
+ </property>
360
+ <property key="action" type="action" required="false">
361
+ <caption>On change</caption>
362
+ <description>Action to be performed when the switch is toggled</description>
363
+ </property>
364
+ </propertyGroup>
373
365
  ```
374
366
 
375
- optional 속성이 있으면 `optional_attr` 헬퍼와 `gleam/option` import가 자동 추가됩니다. Gleam 예약어(`type` 등)는 접미사 `_`로 회피합니다.
376
-
377
- **3단계: 위젯에서 사용**
378
-
379
- 생성된 `src/widgets/*.gleam` 파일을 import하여 사용합니다. 필요에 따라 자유롭게 수정할 수 있습니다.
367
+ **3단계: Gleam 코드에서 사용**
380
368
 
381
369
  ```gleam
382
- import widgets/switch
370
+ import glendix/mendix
371
+ import glendix/widget
372
+ import glendix/react
373
+ import glendix/react/attribute
383
374
 
384
- // 컴포넌트 내부에서
385
- switch.render(props)
375
+ // props에서 자동 주입된 속성을 읽어 위젯에 전달
376
+ let boolean_attr = mendix.get_prop_required(props, "booleanAttribute")
377
+ let action = mendix.get_prop_required(props, "action")
378
+
379
+ // widgets/Switch.mpk의 Switch 컴포넌트 사용
380
+ let switch_comp = widget.component("Switch")
381
+ react.component_el(switch_comp, [
382
+ attribute.attribute("booleanAttribute", boolean_attr),
383
+ attribute.attribute("action", action),
384
+ ], [])
386
385
  ```
387
386
 
388
- 위젯의 Props는 기존 `attribute.attribute(key, value)` 범용 함수로 전달합니다. 위젯 이름은 `.mpk` 내부 XML의 `<name>` 태그 값을, property key는 `.mpk` XML의 원본 key를 그대로 사용합니다.
387
+ 위젯의 Props는 기존 `attribute.attribute(key, value)` 범용 함수로 전달합니다. 위젯 이름은 `.mpk` 내부 XML의 `<name>` 태그 값(PascalCase)을, property key는 `.mpk` XML의 원본 key를 그대로 사용합니다.
389
388
 
390
389
  > `binding` 모듈과 달리 `widget` 모듈은 1 mpk = 1 컴포넌트이므로 `module` + `resolve` 2단계 없이 `component("Name")` 한 번에 가져옵니다.
391
390
 
@@ -1963,6 +1962,135 @@ fn check_icon(size: String) -> ReactElement {
1963
1962
  }
1964
1963
  ```
1965
1964
 
1965
+ ### 5.6 Marketplace 위젯 다운로드
1966
+
1967
+ Mendix Marketplace에서 위젯(.mpk)을 인터랙티브하게 검색하고 다운로드할 수 있습니다. 다운로드 완료 후 바인딩 `.gleam` 파일이 자동 생성되어, 별도의 수동 설정 없이 바로 사용할 수 있습니다.
1968
+
1969
+ #### 사전 준비
1970
+
1971
+ `.env` 파일에 Mendix Personal Access Token을 설정합니다:
1972
+
1973
+ ```
1974
+ MENDIX_PAT=your_personal_access_token
1975
+ ```
1976
+
1977
+ > PAT는 [Mendix Developer Settings](https://user-settings.mendix.com/link/developersettings)에서 **Personal Access Tokens** 섹션의 **New Token**을 클릭하여 발급합니다.
1978
+ > 필요한 scope: `mx:marketplace-content:read`
1979
+
1980
+ #### 실행
1981
+
1982
+ ```bash
1983
+ gleam run -m glendix/marketplace
1984
+ ```
1985
+
1986
+ #### 인터랙티브 TUI
1987
+
1988
+ 실행하면 Content API(`GET /content`)로 위젯 목록을 로드하고, 인터랙티브 TUI가 표시됩니다:
1989
+
1990
+ ```
1991
+ ── 페이지 1/5+ ──
1992
+
1993
+ [0] Star Rating (54611) v3.2.2 — Mendix
1994
+ [1] Switch (50324) v4.0.0 — Mendix
1995
+ [2] Progress Bar (48019) v3.1.0 — Mendix
1996
+ ...
1997
+
1998
+ 번호: 다운로드 | 검색어: 이름 검색 | n: 다음 | p: 이전 | r: 초기화 | q: 종료
1999
+
2000
+ >
2001
+ ```
2002
+
2003
+ **주요 명령어:**
2004
+
2005
+ | 입력 | 동작 |
2006
+ |------|------|
2007
+ | `0` | 0번 위젯 다운로드 |
2008
+ | `0,1,3` | 여러 위젯 동시 다운로드 (쉼표 구분) |
2009
+ | `star` | 이름/퍼블리셔로 검색 필터링 |
2010
+ | `n` / `p` | 다음/이전 페이지 |
2011
+ | `r` | 검색 초기화 (전체 목록 복귀) |
2012
+ | `q` | 종료 |
2013
+
2014
+ #### 버전 선택
2015
+
2016
+ 위젯을 선택하면 버전 목록이 표시됩니다. Pluggable/Classic 타입이 자동 구분됩니다:
2017
+
2018
+ ```
2019
+ Star Rating — 버전 선택:
2020
+
2021
+ [0] v3.2.2 (2024-01-15) (Mendix ≥9.24.0) [Pluggable] ← 기본
2022
+ [1] v3.1.0 (2023-08-20) (Mendix ≥9.18.0) [Pluggable]
2023
+ [2] v2.5.1 (2022-03-10) (Mendix ≥8.0.0) [Classic]
2024
+
2025
+ 버전 번호 (Enter=최신):
2026
+ ```
2027
+
2028
+ Enter를 누르면 최신 버전이 다운로드됩니다.
2029
+
2030
+ #### 동작 흐름
2031
+
2032
+ 1. **첫 배치 로드** — Content API에서 첫 40개 아이템을 직접 로드하여 즉시 표시
2033
+ 2. **백그라운드 로드** — 나머지 아이템을 별도 프로세스에서 비동기 로드 (`.marketplace-cache/`에 캐시)
2034
+ 3. **위젯 선택 시** — Playwright(headless chromium)로 Marketplace 페이지에서 S3 다운로드 URL 추출
2035
+ 4. **다운로드** — S3에서 `.mpk` 파일을 `widgets/` 디렉토리에 저장
2036
+ 5. **바인딩 생성** — `cmd.generate_widget_bindings()`가 자동 호출되어 `src/widgets/`에 바인딩 `.gleam` 파일 생성
2037
+
2038
+ > 버전 정보 조회에 Playwright를 사용하므로, 첫 다운로드 시 브라우저 로그인이 필요합니다. 세션은 `.marketplace-cache/session.json`에 저장되어 이후 재사용됩니다.
2039
+
2040
+ #### 다운로드 후 사용
2041
+
2042
+ 다운로드된 위젯은 자동으로 바인딩이 생성됩니다. Pluggable 위젯과 Classic 위젯은 각각 다른 패턴으로 사용합니다:
2043
+
2044
+ **Pluggable 위젯** (`glendix/widget` 사용):
2045
+
2046
+ ```gleam
2047
+ // src/widgets/star_rating.gleam (자동 생성)
2048
+ import glendix/mendix
2049
+ import glendix/react.{type JsProps, type ReactElement}
2050
+ import glendix/react/attribute
2051
+ import glendix/widget
2052
+
2053
+ pub fn render(props: JsProps) -> ReactElement {
2054
+ let rate_attribute = mendix.get_prop_required(props, "rateAttribute")
2055
+ let comp = widget.component("StarRating")
2056
+ react.component_el(
2057
+ comp,
2058
+ [attribute.attribute("rateAttribute", rate_attribute)],
2059
+ [],
2060
+ )
2061
+ }
2062
+ ```
2063
+
2064
+ **Classic (Dojo) 위젯** (`glendix/classic` 사용):
2065
+
2066
+ ```gleam
2067
+ // src/widgets/camera_widget.gleam (자동 생성)
2068
+ import gleam/dynamic
2069
+ import glendix/classic
2070
+ import glendix/mendix
2071
+ import glendix/react.{type JsProps, type ReactElement}
2072
+
2073
+ pub fn render(props: JsProps) -> ReactElement {
2074
+ let mf_to_execute = mendix.get_prop_required(props, "mfToExecute")
2075
+ classic.render("CameraWidget.widget.CameraWidget", [
2076
+ #("mfToExecute", dynamic.from(mf_to_execute)),
2077
+ ])
2078
+ }
2079
+ ```
2080
+
2081
+ **위젯에서 import:**
2082
+
2083
+ ```gleam
2084
+ import widgets/star_rating
2085
+ import widgets/camera_widget
2086
+
2087
+ // 컴포넌트 내부에서
2088
+ star_rating.render(props)
2089
+ camera_widget.render(props)
2090
+ ```
2091
+
2092
+ 생성된 `src/widgets/*.gleam` 파일은 자유롭게 수정할 수 있으며, 이미 존재하는 파일은 재생성 시 덮어쓰지 않습니다.
2093
+
1966
2094
  ---
1967
2095
 
1968
2096
  ## 6. 트러블슈팅
@@ -1988,6 +2116,11 @@ fn check_icon(size: String) -> ReactElement {
1988
2116
  | `could not be resolved – treating it as an external dependency` | `bindings.json`에 등록한 패키지가 `node_modules`에 없음 | `npm install <패키지명>` 등으로 설치 후 재빌드 |
1989
2117
  | `바인딩에 등록되지 않은 모듈` | `bindings.json`에 해당 패키지 미등록 | `bindings.json`에 패키지와 컴포넌트 추가 후 재설치 |
1990
2118
  | `모듈에 없는 컴포넌트` | `bindings.json`의 `components`에 해당 컴포넌트 미등록 | `components` 배열에 추가 후 재설치 |
2119
+ | `.env 파일에 MENDIX_PAT가 필요합니다` | marketplace 실행 시 PAT 미설정 | `.env`에 `MENDIX_PAT=...` 추가 (scope: `mx:marketplace-content:read`) — [Developer Settings](https://user-settings.mendix.com/link/developersettings)에서 발급 |
2120
+ | `인증 실패 — MENDIX_PAT를 확인하세요` | PAT가 잘못되었거나 만료됨 | [Developer Settings](https://user-settings.mendix.com/link/developersettings)에서 새 PAT 발급 |
2121
+ | `위젯을 불러올 수 없습니다` | Content API 접근 실패 | 네트워크 및 PAT 확인 |
2122
+ | `Playwright 오류` | chromium 미설치 또는 세션 만료 | `npx playwright install chromium` 실행, 또는 브라우저 재로그인 |
2123
+ | `저장된 세션이 만료되었습니다` | Mendix 로그인 세션 만료 | 브라우저 로그인 팝업에서 재로그인 |
1991
2124
 
1992
2125
  ### 일반적인 실수
1993
2126
 
@@ -8,4 +8,4 @@ runtime = "node"
8
8
 
9
9
  [dependencies]
10
10
  gleam_stdlib = ">= 0.44.0 and < 2.0.0"
11
- glendix = ">= 2.0.3 and < 3.0.0"
11
+ glendix = ">= 2.0.4 and < 3.0.0"