@opsnow-mcp/opsnow-mcp-common-ui-server 1.0.21 → 1.0.23

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.
Files changed (41) hide show
  1. package/build/components/data/icon-names.js +129 -0
  2. package/build/components/examples/opsnow-common-calendar-examples-data.js +48 -0
  3. package/build/components/examples/opsnow-common-chart-examples-data.js +6843 -0
  4. package/build/components/examples/opsnow-common-data-status-examples-data.js +65 -0
  5. package/build/components/examples/opsnow-common-file-upload-examples-data.js +95 -0
  6. package/build/components/examples/opsnow-common-forms-examples-data.js +1715 -0
  7. package/build/components/examples/opsnow-common-grid-examples-data.js +2389 -0
  8. package/build/components/examples/opsnow-common-icons-examples-data.js +72 -0
  9. package/build/components/examples/opsnow-common-layout-examples-data.js +97 -0
  10. package/build/components/examples/opsnow-common-notification-examples-data.js +78 -0
  11. package/build/components/examples/opsnow-common-pagination-examples-data.js +82 -0
  12. package/build/components/examples/opsnow-common-popup-examples-data.js +205 -0
  13. package/build/components/examples/opsnow-common-progress-examples-data.js +86 -0
  14. package/build/components/examples/opsnow-common-select-examples-data.js +131 -0
  15. package/build/components/examples/opsnow-common-stepper-examples-data.js +180 -0
  16. package/build/components/examples/opsnow-common-storage-examples-data.js +8 -0
  17. package/build/components/examples/opsnow-common-tab-examples-data.js +87 -0
  18. package/build/components/examples/opsnow-common-toast-popup-examples-data.js +129 -0
  19. package/build/components/examples/opsnow-common-tooltip-examples-data.js +80 -0
  20. package/build/components/examples/opsnow-common-typography-examples-data.js +366 -0
  21. package/build/components/opsnow-common-calendar.js +228 -0
  22. package/build/components/opsnow-common-chart.js +1643 -0
  23. package/build/components/opsnow-common-data-status.js +116 -0
  24. package/build/components/opsnow-common-examples.js +109 -0
  25. package/build/components/opsnow-common-file-upload.js +57 -0
  26. package/build/components/opsnow-common-forms.js +1009 -0
  27. package/build/components/opsnow-common-grid.js +352 -0
  28. package/build/components/opsnow-common-icons.js +139 -0
  29. package/build/components/opsnow-common-layout.js +141 -0
  30. package/build/components/opsnow-common-notification.js +110 -0
  31. package/build/components/opsnow-common-pagination.js +164 -0
  32. package/build/components/opsnow-common-popup.js +71 -0
  33. package/build/components/opsnow-common-progress.js +177 -0
  34. package/build/components/opsnow-common-select.js +135 -0
  35. package/build/components/opsnow-common-stepper.js +72 -0
  36. package/build/components/opsnow-common-tab.js +111 -0
  37. package/build/components/opsnow-common-toast-popup.js +135 -0
  38. package/build/components/opsnow-common-tooltip.js +204 -0
  39. package/build/components/opsnow-common-typography.js +93 -0
  40. package/build/index.js +135 -0
  41. package/package.json +1 -1
@@ -0,0 +1,352 @@
1
+ import { z } from "zod";
2
+ const gridOptionsSchema = z.object({
3
+ animateRows: z.boolean().optional().describe('행 애니메이션 사용 여부'),
4
+ rowSelection: z.object({
5
+ mode: z.enum(['singleRow', 'multiRow']).describe('행 선택 모드'),
6
+ checkboxes: z.boolean().optional().describe('체크박스 사용 여부'),
7
+ enableClickSelection: z.boolean().optional().describe('클릭으로 행 선택 활성화'),
8
+ headerCheckbox: z.boolean().optional().describe('헤더 체크박스 사용 여부'),
9
+ enableSelectionWithoutKeys: z.boolean().optional().describe('키 없이 선택 허용'),
10
+ }).optional().describe('행 선택 옵션'),
11
+ tooltipShowDelay: z.number().optional().describe('툴팁 표시 지연 시간'),
12
+ domLayout: z.enum(['normal', 'autoHeight', 'print']).optional().describe('그리드 레이아웃 방식'),
13
+ suppressCellFocus: z.boolean().optional().describe('셀 포커스 비활성화 (셀 클릭 이벤트 사용 시 필수: true)'),
14
+ suppressPaginationPanel: z.boolean().optional().describe('페이지네이션 패널 숨김'),
15
+ masterDetail: z.boolean().optional().describe('마스터/디테일 모드 사용'),
16
+ detailCellRenderer: z.any().optional().describe('디테일 셀 렌더러'),
17
+ pivotMode: z.boolean().optional().describe('피벗 모드 사용'),
18
+ autoGroupColumnDef: z.record(z.any()).optional().describe('자동 그룹 컬럼 정의'),
19
+ sideBar: z.enum(['columns', 'filters', 'custom']).optional().describe('사이드바 옵션'),
20
+ groupDefaultExpanded: z.number().optional().describe('기본 그룹 확장 단계'),
21
+ treeData: z.boolean().optional().describe('트리 데이터 사용 여부'),
22
+ getDataPath: z.string().optional().describe('트리 데이터 경로 반환 함수(stringified)'),
23
+ setDataPath: z.string().optional().describe('트리 데이터 경로 설정 함수(stringified)'),
24
+ pinnedBottomRowData: z.array(z.record(z.any())).optional().describe('하단 고정 행 데이터'),
25
+ onRowDragEnter: z.string().optional().describe('행 드래그 진입 이벤트 핸들러(stringified)'),
26
+ rowDragMultiRow: z.boolean().optional().describe('다중 행 드래그 사용'),
27
+ rowDragManaged: z.boolean().optional().describe('드래그 관리 모드'),
28
+ suppressMoveWhenRowDragging: z.boolean().optional().describe('드래그 시 이동 억제'),
29
+ alwaysMultiSort: z.boolean().optional().describe('항상 다중 정렬 사용'),
30
+ serverSideSortAllLevels: z.boolean().optional().describe('서버사이드 전체 레벨 정렬'),
31
+ getRowId: z.string().optional().describe('행 ID 반환 함수(stringified)'),
32
+ suppressMenuHide: z.boolean().optional().describe('메뉴 숨김 억제'),
33
+ });
34
+ const columnDefsSchema = z.lazy(() => z.object({
35
+ headerName: z.string().optional().describe('컬럼 헤더명'),
36
+ field: z.string().optional().describe('컬럼 데이터 필드명'),
37
+ colId: z.string().optional().describe('컬럼 고유 ID'),
38
+ groupId: z.string().optional().describe('컬럼 그룹 고유 ID'),
39
+ width: z.number().optional().describe('컬럼 너비'),
40
+ minWidth: z.number().describe('컬럼 최소 너비'),
41
+ maxWidth: z.number().optional().describe('컬럼 최대 너비'),
42
+ pinned: z.enum(['left', 'right']).optional().describe('컬럼 고정 위치'),
43
+ type: z.array(z.enum([
44
+ 'number',
45
+ 'cost',
46
+ 'ratio',
47
+ 'mixFormat',
48
+ 'numberTooltip',
49
+ 'ratioBar',
50
+ 'dataBar',
51
+ 'value'
52
+ ])).optional().describe(`컬럼 타입.
53
+ - ratioBar: 여러 색상/세그먼트로 구성 비율을 보여주는 스택 차트 스타일 바. 여러 필드의 비율을 시각화할 때 사용 (예: Cost Composition by Type). 'Ratio Bar' 예제 참고.
54
+ - dataBar: 단일 색상으로 셀 배경을 값에 비례하여 채우는 Excel 스타일 바. 단일 값의 크기를 시각화할 때 사용 (예: 월별 비용 트렌드). 'Data Bar' 예제 참고.`),
55
+ cellRenderer: z.any().optional().describe('셀 렌더러'),
56
+ cellRendererParams: z.object({
57
+ typeParams: z.object({
58
+ currency: z.string().optional().describe('통화 단위'),
59
+ digits: z.number().optional().describe('소수점 자리수'),
60
+ iconRight: z.boolean().optional().describe('오른쪽 아이콘 표시'),
61
+ isPercent: z.boolean().optional().describe('퍼센트 표시 여부'),
62
+ fields: z.array(z.string()).optional().describe('비율바 등에서 여러 필드'),
63
+ label: z.object({
64
+ postfix: z.string().optional().describe('라벨 접미사'),
65
+ location: z.enum(['left', 'right']).optional().describe('라벨 위치'),
66
+ }).optional().describe('라벨 옵션'),
67
+ value: z.object({
68
+ type: z.string().optional().describe('값 타입'),
69
+ }).optional().describe('값 옵션'),
70
+ }).catchall(z.any()).optional().describe('타입별 파라미터'),
71
+ component: z.any().optional().describe('커스텀 렌더러 컴포넌트'),
72
+ }).catchall(z.any()).optional().describe('셀 렌더러 파라미터'),
73
+ headerComponent: z.any().optional().describe('헤더 컴포넌트'),
74
+ headerComponentParams: z.object({
75
+ displayData1: z.string().optional().describe('헤더 표시 데이터 1'),
76
+ tooltipInfoText: z.string().optional().describe('헤더 툴팁 텍스트'),
77
+ filter: z.boolean().optional().describe('필터 사용 여부'),
78
+ filterParams: z.object({
79
+ showTooltips: z.boolean().optional().describe('툴팁 표시 여부'),
80
+ values: z.string().describe('필터 값 목록 또는 동적 값 제공 함수'),
81
+ }).catchall(z.any()).optional().describe('필터 파라미터'),
82
+ tooltipField: z.string().optional().describe('툴팁에 사용할 필드명'),
83
+ dropdownList: z.array(z.string()).optional().describe('드롭다운 리스트'),
84
+ defaultValue: z.any().optional().describe('드롭다운 등에서의 기본값'),
85
+ isUsedMenuFilter: z.boolean().optional().describe('메뉴/필터 버튼 노출 여부'),
86
+ }).catchall(z.any()).optional().describe('헤더 컴포넌트 파라미터'),
87
+ sortable: z.boolean().optional().describe('정렬 가능 여부'),
88
+ resizable: z.boolean().optional().describe('크기 조절 가능 여부'),
89
+ wrapText: z.boolean().optional().describe('텍스트 줄바꿈'),
90
+ autoHeight: z.boolean().optional().describe('자동 높이'),
91
+ suppressMenu: z.boolean().optional().describe('메뉴 숨김'),
92
+ unSortIcon: z.boolean().optional().describe('정렬 해제 아이콘 표시'),
93
+ rowDrag: z.boolean().optional().describe('행 드래그 사용'),
94
+ rowDragText: z.string().optional().describe('행 드래그 텍스트 함수(stringified)'),
95
+ valueFormatter: z.string().optional().describe('값 포맷터 함수(stringified)'),
96
+ cellStyle: z.record(z.any()).optional().describe('셀 스타일'),
97
+ hide: z.boolean().optional().describe('컬럼 숨김 여부'),
98
+ aggFunc: z.enum(['sum', 'min', 'max', 'count', 'avg']).optional().describe('집계 함수'),
99
+ enableRowGroup: z.boolean().optional().describe('행 그룹핑 허용'),
100
+ enablePivot: z.boolean().optional().describe('피벗 허용'),
101
+ enableValue: z.boolean().optional().describe('값 집계 허용'),
102
+ pivot: z.boolean().optional().describe('피벗 컬럼 여부'),
103
+ rowGroup: z.boolean().optional().describe('그룹핑 컬럼 여부'),
104
+ filter: z.boolean().optional().describe('필터 사용 여부'),
105
+ filterParams: z.any().optional().describe('필터 파라미터'),
106
+ cellRendererSelector: z.string().optional().describe('셀 렌더러 선택 함수(stringified)'),
107
+ colSpan: z.string().optional().describe('컬럼 병합 함수(stringified)'),
108
+ children: z.array(z.lazy(() => columnDefsSchema)).optional().describe('하위 컬럼 정의 배열 (컬럼 그룹화)'),
109
+ }));
110
+ const defaultColDefSchema = z.object({
111
+ wrapText: z.boolean().optional().describe('텍스트 줄바꿈'),
112
+ autoHeight: z.boolean().optional().describe('자동 높이'),
113
+ suppressMenu: z.boolean().optional().describe('메뉴 숨김'),
114
+ unSortIcon: z.boolean().optional().describe('정렬 해제 아이콘 표시'),
115
+ sortable: z.boolean().optional().describe('정렬 가능 여부'),
116
+ resizable: z.boolean().optional().describe('크기 조절 가능 여부'),
117
+ flex: z.number().optional().describe('flex 비율'),
118
+ suppressHeaderMenuButton: z.boolean().optional().describe('헤더 메뉴 버튼 숨김'),
119
+ minWidth: z.number().optional().describe('최소 너비'),
120
+ maxWidth: z.number().optional().describe('최대 너비'),
121
+ width: z.number().optional().describe('기본 너비'),
122
+ });
123
+ // ag-grid 기반 OpsnowCommonDataGrid 스키마 정의
124
+ export const DataGridSchema = z.object({
125
+ totalPage: z.number().optional().describe('전체 페이지 수'),
126
+ initPageNum: z.number().optional().describe('초기 페이지 번호'),
127
+ dropdownSearchDefaultValue: z.string().optional().describe('드롭다운 검색 기본값'),
128
+ gridOptions: gridOptionsSchema.optional().describe('ag-grid 옵션'),
129
+ columnDefs: z.array(columnDefsSchema).describe("ag-grid 컬럼 정의").min(1),
130
+ defaultColDef: defaultColDefSchema.optional().describe('ag-grid 기본 컬럼 옵션'),
131
+ rowData: z.array(z.record(z.any())).optional().describe('그리드에 표시할 데이터'),
132
+ status: z.number().describe(`그리드 상태값: GRID.STATUS.LOADING(0), GRID.STATUS.DATA_EXISTS(1), GRID.STATUS.ERROR(9) 중 하나를 사용해야 합니다.
133
+
134
+ **필수 구현 패턴:**
135
+ 반드시 useState로 상태를 관리하고, useEffect 등을 사용하여 데이터 로딩 로직을 구현해야 합니다.
136
+ 사용자는 이 상태 제어 코드 안에 실제 비즈니스 로직(API 호출, 데이터 처리 등)을 추가할 수 있습니다.
137
+
138
+ 예제:
139
+ const [status, setStatus] = useState(CommonConst.GRID_STATUS.LOADING)
140
+ const [rowData, setRowData] = useState([])
141
+
142
+ useEffect(() => {
143
+ // 여기에 실제 비즈니스 로직을 추가합니다 (예: API 호출)
144
+ fetchData()
145
+ .then(data => {
146
+ setRowData(data)
147
+ setStatus(CommonConst.GRID_STATUS.DATA_EXISTS)
148
+ })
149
+ .catch(error => {
150
+ setStatus(CommonConst.GRID_STATUS.ERROR)
151
+ })
152
+ }, [])`),
153
+ gridHeight: z.number().optional().describe('그리드 높이'),
154
+ setClass: z.string().optional().describe('그리드 클래스명'),
155
+ localRowClass: z.string().optional().describe('로컬 행 클래스명'),
156
+ pagination: z.boolean().optional().describe('페이지네이션 사용 여부 (true로 설정 시 내부적으로 opsnow-common-pagination 컴포넌트 사용)'),
157
+ paginationPageSize: z.number().optional().describe('페이지당 행 수'),
158
+ textNoData: z.string().optional().describe('데이터 없음 텍스트'),
159
+ noDataDescription: z.string().optional().describe('데이터 없음 설명'),
160
+ textLoading: z.string().optional().describe('로딩 중 텍스트'),
161
+ textErrorTitle: z.string().optional().describe('에러 타이틀'),
162
+ textErrorDescription: z.string().optional().describe('에러 설명'),
163
+ filterSearchText: z.string().optional().describe('필터 검색 텍스트'),
164
+ searchTextNoData: z.string().optional().describe('검색 결과 없음 텍스트'),
165
+ searchTextNoDataDescription: z.string().optional().describe('검색 결과 없음 설명'),
166
+ pagingFromServer: z.boolean().optional().describe('서버 페이징 사용 여부'),
167
+ pageSizeList: z.array(z.object({
168
+ label: z.string().describe('페이지 사이즈 라벨'),
169
+ value: z.number().describe('페이지 사이즈 값')
170
+ })).optional().describe('페이지 사이즈 리스트 (예: [{ label: "5", value: 5 }, { label: "10", value: 10 }])'),
171
+ placeholderText: z.string().optional().describe('플레이스홀더 텍스트'),
172
+ usedRowClass: z.boolean().optional().describe('행 클래스 사용 여부 (셀 클릭 이벤트 사용 시 필수: true)'),
173
+ usedSearch: z.boolean().optional().describe('검색창 사용 여부'),
174
+ usedSearchAndDropdown: z.boolean().optional().describe('검색+드롭다운 동시 사용'),
175
+ useOpsnowUs: z.boolean().optional().describe('Opsnow US 스타일 사용'),
176
+ inTile: z.boolean().optional().describe('타일 내 그리드 여부'),
177
+ noDataCustomComponent: z.any().optional().describe('커스텀 No Data 컴포넌트'),
178
+ rowModelType: z.string().optional().describe('행 모델 타입'),
179
+ serverSideDatasource: z.record(z.any()).optional().describe('서버사이드 데이터소스'),
180
+ cacheBlockSize: z.number().optional().describe('서버사이드 캐시 블록 크기'),
181
+ usedMenuItem: z.boolean().optional().describe('메뉴 아이템 사용 여부'),
182
+ showSelectedRowCount: z.boolean().optional().describe('선택 행 개수 표시'),
183
+ isAutoSizeAllColumns: z.boolean().optional().describe('모든 컬럼 자동 크기 조정'),
184
+ langCd: z.string().optional().describe('언어 코드'),
185
+ useTreeDataDragDrop: z.boolean().optional().describe('트리 데이터 드래그 사용'),
186
+ getDropTargetNode: z.string().optional().describe('드롭 타겟 노드 반환 함수(stringified)'),
187
+ emitQuickFilterChange: z.boolean().optional().describe('빠른 필터 변경 이벤트 발생'),
188
+ searchAddon: z.any().optional().describe('검색창 왼쪽 추가 컴포넌트'),
189
+ children: z.any().optional().describe('그리드 children'),
190
+ onGridReady: z.string().optional().describe('그리드 준비 이벤트 핸들러(stringified)'),
191
+ onFirstDataRendered: z.string().optional().describe('첫 데이터 렌더링 이벤트 핸들러(stringified)'),
192
+ onGridSizeChanged: z.string().optional().describe('그리드 크기 변경 이벤트 핸들러(stringified)'),
193
+ onSelectionChanged: z.string().optional().describe('선택 변경 이벤트 핸들러(stringified)'),
194
+ onCellClick: z.string().optional().describe('셀 클릭 이벤트 핸들러(stringified)'),
195
+ onFilterChanged: z.string().optional().describe('필터 변경 이벤트 핸들러(stringified)'),
196
+ onUpdateFilter: z.string().optional().describe('필터 업데이트 이벤트 핸들러(stringified)'),
197
+ onSearchQueryChanged: z.string().optional().describe('검색어 변경 이벤트 핸들러(stringified)'),
198
+ onSetPage: z.string().optional().describe('페이지 변경 이벤트 핸들러(stringified)'),
199
+ serverSideTotalPageSize: z.number().optional().describe('서버사이드 전체 페이지 수')
200
+ });
201
+ // DataGrid 컴포넌트 함수 - 배열 반환
202
+ export function createDataGridComponent() {
203
+ return [
204
+ {
205
+ name: "createDataGrid",
206
+ description: `데이터 그리드 컴포넌트 - 데이터를 테이블로 표시 및 관리하는 컴포넌트로 레이아웃을 구성하는 Grid와 구별되는 컴포넌트입니다.
207
+
208
+ **이 데이터 그리드 컴포넌트는 ag-grid를 기반으로 구현되었습니다.**
209
+ **데이터 그리드 데이터, 컬럼 정의 등의 데이터가 제공되지 않을 경우 목업 데이터를 사용하세요.**
210
+
211
+ **CRITICAL: Auto Row Height - 다음 경우 반드시 적용**
212
+ 1. 긴 텍스트가 들어올 수 있는 컬럼이 있는 경우 (설명, 메시지, 항목, 이름, 제목, 코멘트, 비고, 등)
213
+ 2. 컬럼이 resizable인 경우 - 사용자가 폭을 줄여도 텍스트가 잘리지 않고 여러 줄로 정상 표시되어야 함 (ellipsis로 자르면 안됨)
214
+
215
+ [필수] defaultColDef에 반드시 포함:
216
+ const defaultColDef = {
217
+ // ... 다른 설정들
218
+ wrapText: true, // 필수 - 텍스트 줄바꿈
219
+ autoHeight: true, // 필수 - 행 높이 자동 조절
220
+ };
221
+
222
+ [필수] gridOptions에 반드시 포함:
223
+ const gridOptions = {
224
+ // ... 다른 설정들
225
+ domLayout: 'autoHeight', // 필수
226
+ };
227
+
228
+ [필수] 텍스트 컬럼에 반드시 포함:
229
+ {
230
+ headerName: '설명',
231
+ field: 'description',
232
+ flex: 2, // 필수 - flex 사용
233
+ minWidth: 200,
234
+ wrapText: true, // 필수 - 텍스트 줄바꿈
235
+ autoHeight: true, // 필수 - 행 높이 자동 조절
236
+ suppressSizeToFit: true, // 필수
237
+ cellStyle: { alignItems: 'center' } // 필수 (flex-start도 가능)
238
+ }
239
+
240
+ ⚠️ defaultColDef에 wrapText, autoHeight가 없으면 텍스트가 넘칩니다!
241
+
242
+ **import:**
243
+ \`\`\`javascript
244
+ import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader';
245
+ const { OpsnowCommonDataGrid } = useCommonComponents();
246
+ const { CommonConst } = useGlobalContext();
247
+ \`\`\`
248
+
249
+ **중요: 상태 관리 패턴 (필수 구현)**
250
+ 데이터 그리드를 구현할 때는 반드시 아래의 세 가지 상태(LOADING, DATA_EXISTS, ERROR)를 모두 처리하는 코드를 포함해야 합니다.
251
+
252
+ **절대 하지 말아야 할 것:**
253
+ - useState에 직접 데이터를 넣지 마세요: const [rowData] = useState([{...}]) ❌
254
+ - status를 바로 DATA_EXISTS로 설정하지 마세요: const [status] = useState(CommonConst.GRID_STATUS.DATA_EXISTS) ❌
255
+ - useEffect 없이 구현하지 마세요 ❌
256
+
257
+ **반드시 따라야 할 구현 패턴:**
258
+ 1. status는 반드시 CommonConst.GRID_STATUS.LOADING으로 시작
259
+ 2. rowData는 반드시 빈 배열 []로 시작
260
+ 3. useEffect를 반드시 사용하여 데이터 로딩 시뮬레이션
261
+ 4. .then()으로 성공 처리 → CommonConst.GRID_STATUS.DATA_EXISTS로 변경
262
+ 5. .catch()로 에러 처리 → CommonConst.GRID_STATUS.ERROR로 변경
263
+ 6. OpsnowCommonDataGrid에 textErrorTitle, textErrorDescription 속성 반드시 포함
264
+
265
+ 사용자는 생성된 코드의 useEffect 내부에 실제 비즈니스 로직(API 호출, 데이터 변환 등)을 추가할 수 있습니다.
266
+
267
+ **기본 패턴 예제 (정확히 이 구조를 따라야 함):**
268
+ \`\`\`javascript
269
+ // ✅ 올바른 방법: LOADING으로 시작, 빈 배열로 시작
270
+ const [status, setStatus] = useState(CommonConst.GRID_STATUS.LOADING);
271
+ const [rowData, setRowData] = useState([]);
272
+
273
+ // ✅ 올바른 방법: useEffect에서 데이터 로딩
274
+ useEffect(() => {
275
+ // 사용자가 여기에 실제 API 호출 등 비즈니스 로직을 추가합니다
276
+ const fetchData = async () => {
277
+ try {
278
+ // 실제로는 여기에 API 호출을 넣습니다
279
+ // 예: const response = await fetch('/api/data');
280
+ // const data = await response.json();
281
+
282
+ // 데모를 위한 시뮬레이션
283
+ await new Promise(resolve => setTimeout(resolve, 1000));
284
+
285
+ const mockData = [
286
+ { make: 'Toyota', model: 'Celica', price: 35000 },
287
+ { make: 'Ford', model: 'Mondeo', price: 32000 }
288
+ ];
289
+
290
+ setRowData(mockData);
291
+ setStatus(CommonConst.GRID_STATUS.DATA_EXISTS);
292
+ } catch (error) {
293
+ console.error('Error loading data:', error);
294
+ setStatus(CommonConst.GRID_STATUS.ERROR);
295
+ }
296
+ };
297
+
298
+ fetchData();
299
+ }, []);
300
+
301
+ // gridOptions 정의 (권장)
302
+ const gridOptions = {
303
+ animateRows: true,
304
+ rowSelection: { mode: 'singleRow', checkboxes: false, enableClickSelection: true },
305
+ tooltipShowDelay: 100,
306
+ domLayout: 'autoHeight',
307
+ suppressCellFocus: true,
308
+ };
309
+
310
+ // ✅ 올바른 방법: 에러 관련 속성 포함
311
+ <OpsnowCommonDataGrid
312
+ columnDefs={columnDefs}
313
+ rowData={rowData}
314
+ status={status}
315
+ gridOptions={gridOptions}
316
+ pagination={true}
317
+ paginationPageSize={5}
318
+ pageSizeList={[
319
+ { label: '5', value: 5 },
320
+ { label: '10', value: 10 },
321
+ { label: '20', value: 20 }
322
+ ]}
323
+ textErrorTitle="데이터 로드 실패"
324
+ textErrorDescription="데이터를 불러오는 중 오류가 발생했습니다."
325
+ langCd={i18n.getLocale()}
326
+ />
327
+ \`\`\``,
328
+ parameters: DataGridSchema,
329
+ handler: async (args) => {
330
+ // DataGridSchema의 모든 속성을 JSX prop으로 변환
331
+ const props = [];
332
+ const argsObj = args;
333
+ for (const key in argsObj) {
334
+ if (argsObj[key] === undefined || argsObj[key] === null)
335
+ continue;
336
+ if (typeof argsObj[key] === 'function')
337
+ continue;
338
+ props.push(`${key}={${JSON.stringify(argsObj[key])}}`);
339
+ }
340
+ const code = `<OpsnowCommonDataGrid ${props.join(' ')} />`;
341
+ return {
342
+ content: [
343
+ {
344
+ type: "text",
345
+ text: `\`\`\`jsx\n${code}\n\`\`\``
346
+ }
347
+ ]
348
+ };
349
+ }
350
+ }
351
+ ];
352
+ }
@@ -0,0 +1,139 @@
1
+ import { z } from "zod";
2
+ import { IconNamesMap, generateIconDescription } from "./data/icon-names.js";
3
+ export const IconSchema = z.object({
4
+ iconName: z.enum(Object.keys(IconNamesMap)).describe(generateIconDescription({ format: 'nested' })),
5
+ size: z.number().optional().default(24).describe("아이콘 크기(px)"),
6
+ color: z.string().optional().describe("아이콘 색상"),
7
+ className: z.string().optional().describe("추가 CSS 클래스"),
8
+ onClick: z.string().optional().describe("클릭 이벤트 핸들러 함수명"),
9
+ disabled: z.boolean().optional().default(false).describe("비활성화 여부")
10
+ });
11
+ export const MuiIconSchema = z.object({
12
+ theme: z.string().optional().describe("테마명"),
13
+ hexColor: z.string().optional().describe("HEX 색상"),
14
+ size: z.number().optional().default(24).describe("아이콘 크기(px)"),
15
+ noCircle: z.boolean().optional().describe("원형 배경 없음"),
16
+ alpha: z.number().optional().describe("투명도"),
17
+ color: z.string().optional().describe("MUI 색상"),
18
+ label: z.string().optional().describe("MUI 아이콘 이름")
19
+ });
20
+ // export const MarkersSchema = z.object({
21
+ // theme: z.string().describe("마커 테마"),
22
+ // hexColor: z.string().optional().describe("HEX 색상"),
23
+ // lineAlpha: z.number().optional().describe("선 투명도"),
24
+ // size: z.number().optional().default(24).describe("마커 크기(px)")
25
+ // });
26
+ // export type MarkersProps = z.infer<typeof MarkersSchema>;
27
+ export function createIconsComponent() {
28
+ return [
29
+ {
30
+ name: "createIcon",
31
+ description: `아이콘 컴포넌트 - iconName으로 다양한 아이콘 표시
32
+
33
+ - iconName에 사용할 수 있는 아이콘 목록은 IconNamesMap을 참고하세요.
34
+ - 크기, 색상, 비활성화 등 다양한 옵션 지원
35
+ - 아이콘은 useOpsnowCommonIcons 훅을 통해 생성해야 합니다.
36
+
37
+ **import 예시(React의 모든 훅(useState, useEffect, useOpsnowCommonIcons 등)은 반드시 함수 컴포넌트 내부에서 호출):**
38
+
39
+ \`\`\`javascript
40
+ import { useOpsnowCommonIcons } from '@opsnow-common/opsnow-finops-common-ui-loader';
41
+ const { OpsnowCommonIcon } = useOpsnowCommonIcons();
42
+ \`\`\``,
43
+ parameters: IconSchema,
44
+ handler: async (args) => {
45
+ const props = [];
46
+ props.push(`iconName="${args.iconName}"`);
47
+ if (args.size)
48
+ props.push(`size={${args.size}}`);
49
+ if (args.color)
50
+ props.push(`color="${args.color}"`);
51
+ if (args.className)
52
+ props.push(`className="${args.className}"`);
53
+ if (args.onClick)
54
+ props.push(`onClick={${args.onClick}}`);
55
+ if (args.disabled)
56
+ props.push(`disabled`);
57
+ const code = `<OpsnowCommonIcon ${props.join(" ")} />`;
58
+ return {
59
+ content: [
60
+ {
61
+ type: "text",
62
+ text: `\`\`\`jsx\n${code}\n\`\`\``
63
+ }
64
+ ]
65
+ };
66
+ }
67
+ },
68
+ {
69
+ name: "createMuiIcon",
70
+ description: `MUI/커스텀 아이콘 컴포넌트
71
+
72
+ - MUI 아이콘 또는 커스텀 SVG 아이콘을 표시할 수 있습니다.
73
+ - theme, hexColor, noCircle, alpha 등 다양한 스타일 옵션 지원
74
+ - 아이콘은 useOpsnowCommonIcons 훅을 통해 생성해야 합니다.
75
+
76
+ **import 예시:**
77
+ \`\`\`javascript
78
+ import { useOpsnowCommonIcons } from '@opsnow-common/opsnow-finops-common-ui-loader';
79
+ const { OpsnowCommonMuiIcon } = useOpsnowCommonIcons();
80
+ \`\`\``,
81
+ parameters: MuiIconSchema,
82
+ handler: async (args) => {
83
+ const props = [];
84
+ if (args.theme)
85
+ props.push(`theme="${args.theme}"`);
86
+ if (args.hexColor)
87
+ props.push(`hexColor="${args.hexColor}"`);
88
+ if (args.size)
89
+ props.push(`size={${args.size}}`);
90
+ if (args.noCircle)
91
+ props.push(`noCircle`);
92
+ if (args.alpha)
93
+ props.push(`alpha={${args.alpha}}`);
94
+ if (args.color)
95
+ props.push(`color="${args.color}"`);
96
+ if (args.label)
97
+ props.push(`label="${args.label}"`);
98
+ const code = `<OpsnowCommonMuiIcon ${props.join(" ")} />`;
99
+ return {
100
+ content: [
101
+ {
102
+ type: "text",
103
+ text: `\`\`\`jsx\n${code}\n\`\`\``
104
+ }
105
+ ]
106
+ };
107
+ }
108
+ },
109
+ // {
110
+ // name: "createMarkers",
111
+ // description: `마커 컴포넌트 - 그래프/차트용 심볼
112
+ // - 그래프, 차트 등에서 포인트/마커로 활용
113
+ // - theme(마커 테마), hexColor, lineAlpha, size 등 다양한 옵션 지원
114
+ // - 아이콘은 useOpsnowCommonIcons 훅을 통해 생성해야 합니다.
115
+ // **import 예시:**
116
+ // \`\`\`javascript
117
+ // import { useOpsnowCommonIcons } from '@opsnow-common/opsnow-finops-common-ui-loader';
118
+ // const { OpsnowCommonMarkers } = useOpsnowCommonIcons();
119
+ // \`\`\``,
120
+ // parameters: MarkersSchema,
121
+ // handler: async (args: MarkersProps) => {
122
+ // const props: string[] = [];
123
+ // props.push(`theme="${args.theme}"`);
124
+ // if (args.hexColor) props.push(`hexColor="${args.hexColor}"`);
125
+ // if (args.lineAlpha) props.push(`lineAlpha={${args.lineAlpha}}`);
126
+ // if (args.size) props.push(`size={${args.size}}`);
127
+ // const code = `<OpsnowCommonMarkers ${props.join(" ")} />`;
128
+ // return {
129
+ // content: [
130
+ // {
131
+ // type: "text" as const,
132
+ // text: `\`\`\`jsx\n${code}\n\`\`\``
133
+ // }
134
+ // ]
135
+ // };
136
+ // }
137
+ // }
138
+ ];
139
+ }
@@ -0,0 +1,141 @@
1
+ import { z } from "zod";
2
+ const GridLayoutSchema = z.object({
3
+ items: z.array(z.string()).describe("렌더링할 JSX 문자열 배열 (각 항목은 컴포넌트 호출 코드)"),
4
+ layout: z.array(z.object({
5
+ xs: z.number().optional(),
6
+ sm: z.number().optional(),
7
+ md: z.number().optional(),
8
+ lg: z.number().optional(),
9
+ xl: z.number().optional(),
10
+ }).partial()).optional().describe("각 항목별 브레이크포인트 레이아웃 배열"),
11
+ defaultLayout: z.object({
12
+ xs: z.number().optional(),
13
+ sm: z.number().optional(),
14
+ md: z.number().optional(),
15
+ lg: z.number().optional(),
16
+ xl: z.number().optional(),
17
+ }).optional().describe("기본 브레이크포인트 레이아웃"),
18
+ spacing: z.number().optional().describe("Grid 간격 (MUI spacing 단위)"),
19
+ tileProps: z.record(z.any()).optional().describe("OpsnowCommonTile에 전달할 추가 props"),
20
+ });
21
+ const MegaFilterSchema = z.object({
22
+ filters: z.string().describe("필터 배열 변수명"),
23
+ vendors: z.string().optional().describe("벤더 옵션 배열 변수명"),
24
+ selectedVendor: z.string().optional().describe("선택된 벤더 상태 변수명"),
25
+ onVendorChange: z.string().optional().describe("벤더 변경 이벤트 핸들러"),
26
+ onFilterChange: z.string().optional().describe("필터 변경 이벤트 핸들러"),
27
+ selectedDateRange: z.string().optional().describe("선택된 날짜 범위 상태 변수명"),
28
+ onDateRangeChange: z.string().optional().describe("날짜 범위 변경 이벤트 핸들러"),
29
+ locale: z.enum(["en", "ko"]).optional().describe("로케일 설정"),
30
+ title: z.string().optional().describe("필터 제목"),
31
+ clearAllText: z.string().optional().describe("전체 초기화 버튼 텍스트"),
32
+ clearText: z.string().optional().describe("개별 초기화 버튼 텍스트"),
33
+ applyText: z.string().optional().describe("적용 버튼 텍스트"),
34
+ cancelText: z.string().optional().describe("취소 버튼 텍스트"),
35
+ searchPlaceholder: z.string().optional().describe("검색 입력 placeholder"),
36
+ noItemsText: z.string().optional().describe("검색 결과 없음 텍스트"),
37
+ addText: z.string().optional().describe("개별 필터 추가 버튼 텍스트"),
38
+ });
39
+ export function createGridLayoutComponent() {
40
+ return [
41
+ {
42
+ name: "createGridLayout",
43
+ description: `Grid 및 Box 기반 레이아웃 생성
44
+
45
+ **import:**
46
+ \`\`\`jsx
47
+ import { Box, Grid } from '@mui/material';
48
+ \`\`\`
49
+ `,
50
+ parameters: GridLayoutSchema,
51
+ handler: async (args) => {
52
+ const { items, layout = [], defaultLayout = { xs: true }, spacing = 2, } = args;
53
+ const gridItems = items.map((item, i) => {
54
+ const bp = layout[i] || defaultLayout;
55
+ const bpProps = Object.entries(bp)
56
+ .map(([k, v]) => `${k}={${v}}`)
57
+ .join(" ");
58
+ return ` <Grid item ${bpProps} key={${i}}>` +
59
+ `\n <Box sx={{` +
60
+ `\n border: '1px solid #ddd',` +
61
+ `\n borderRadius: '12px',` +
62
+ `\n padding: 2,` +
63
+ `\n display: 'flex',` +
64
+ `\n flexDirection: 'column',` +
65
+ `\n boxShadow: '2px 2px 8px 0 #4254663D',` +
66
+ `\n }}>` +
67
+ `\n ${item}` +
68
+ `\n </Box>` +
69
+ `\n </Grid>`;
70
+ }).join("\n");
71
+ const code = [
72
+ `<Grid container wrap="nowrap" spacing={0} sx={{ padding: '27px', gap: '27px' }}>`,
73
+ gridItems,
74
+ `</Grid>`,
75
+ ].join("\n");
76
+ return {
77
+ content: [
78
+ {
79
+ type: "text",
80
+ text: `\`\`\`jsx\n${code}\n\`\`\``
81
+ }
82
+ ]
83
+ };
84
+ },
85
+ },
86
+ {
87
+ name: "createMegaFilter",
88
+ description: `MegaFilter 컴포넌트 - 다양한 필터, 벤더 선택, 날짜 범위 등 지원
89
+
90
+ **import:**
91
+ \`\`\`javascript
92
+ import { OpsnowCommonMegaFilter } from '@opsnow-common/opsnow-common-layout';
93
+ \`\`\``,
94
+ parameters: MegaFilterSchema,
95
+ handler: async (args) => {
96
+ const props = [];
97
+ if (args.filters)
98
+ props.push(`filters={${args.filters}}`);
99
+ if (args.vendors)
100
+ props.push(`vendors={${args.vendors}}`);
101
+ if (args.selectedVendor)
102
+ props.push(`selectedVendor={${args.selectedVendor}}`);
103
+ if (args.onVendorChange)
104
+ props.push(`onVendorChange={${args.onVendorChange}}`);
105
+ if (args.onFilterChange)
106
+ props.push(`onFilterChange={${args.onFilterChange}}`);
107
+ if (args.selectedDateRange)
108
+ props.push(`selectedDateRange={${args.selectedDateRange}}`);
109
+ if (args.onDateRangeChange)
110
+ props.push(`onDateRangeChange={${args.onDateRangeChange}}`);
111
+ if (args.locale)
112
+ props.push(`locale="${args.locale}"`);
113
+ if (args.title)
114
+ props.push(`title="${args.title}"`);
115
+ if (args.clearAllText)
116
+ props.push(`clearAllText="${args.clearAllText}"`);
117
+ if (args.clearText)
118
+ props.push(`clearText="${args.clearText}"`);
119
+ if (args.applyText)
120
+ props.push(`applyText="${args.applyText}"`);
121
+ if (args.cancelText)
122
+ props.push(`cancelText="${args.cancelText}"`);
123
+ if (args.searchPlaceholder)
124
+ props.push(`searchPlaceholder="${args.searchPlaceholder}"`);
125
+ if (args.noItemsText)
126
+ props.push(`noItemsText="${args.noItemsText}"`);
127
+ if (args.addText)
128
+ props.push(`addText="${args.addText}"`);
129
+ const code = `<OpsnowCommonMegaFilter\n ${props.join('\n ')}\n/>`;
130
+ return {
131
+ content: [
132
+ {
133
+ type: "text",
134
+ text: `\`\`\`jsx\n${code}\n\`\`\``
135
+ }
136
+ ]
137
+ };
138
+ },
139
+ }
140
+ ];
141
+ }