create-mendix-widget-gleam 2.0.2 → 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 +2 -1
- package/package.json +1 -1
- package/src/index.mjs +29 -2
- package/template/.env +1 -0
- package/template/docs/glendix_guide.md +166 -33
- package/template/gleam.toml +1 -1
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.
|
|
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
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}
|
|
158
|
-
${CYAN}gleam run -m glendix/build${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>`
|
|
347
|
+
- `.mpk` XML의 `<property>` 정의가 부모 위젯 XML(`src/{WidgetName}.xml`)에 `<propertyGroup caption="{위젯명}">` 으로 자동 주입됩니다 (동일 caption이 이미 있으면 건너뜀)
|
|
348
348
|
|
|
349
|
-
예를 들어 `Switch.mpk`를 설치하면,
|
|
349
|
+
예를 들어 `Switch.mpk`를 설치하면, 부모 위젯 XML에 다음이 자동 추가됩니다:
|
|
350
350
|
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
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
|
-
|
|
376
|
-
|
|
377
|
-
**3단계: 위젯에서 사용**
|
|
378
|
-
|
|
379
|
-
생성된 `src/widgets/*.gleam` 파일을 import하여 사용합니다. 필요에 따라 자유롭게 수정할 수 있습니다.
|
|
367
|
+
**3단계: Gleam 코드에서 사용**
|
|
380
368
|
|
|
381
369
|
```gleam
|
|
382
|
-
import
|
|
370
|
+
import glendix/mendix
|
|
371
|
+
import glendix/widget
|
|
372
|
+
import glendix/react
|
|
373
|
+
import glendix/react/attribute
|
|
383
374
|
|
|
384
|
-
//
|
|
385
|
-
|
|
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>` 태그
|
|
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
|
|
package/template/gleam.toml
CHANGED