@opsnow-mcp/opsnow-mcp-common-ui-server 1.0.9 → 1.0.10

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.
@@ -1978,7 +1978,11 @@ export const DataGridExamples = [
1978
1978
  usedSearch={true}
1979
1979
  pagination={true}
1980
1980
  paginationPageSize={5}
1981
- pageSizeList={[5, 10]}
1981
+ pageSizeList={[
1982
+ { label: '5', value: 5 },
1983
+ { label: '10', value: 10 },
1984
+ { label: '20', value: 20 },
1985
+ ]}
1982
1986
  langCd={i18n.getLocale()}
1983
1987
  />`
1984
1988
  },
@@ -2083,4 +2087,130 @@ export const DataGridExamples = [
2083
2087
  langCd={i18n.getLocale()}
2084
2088
  />`
2085
2089
  },
2090
+ {
2091
+ title: 'Error Status',
2092
+ description: 'Error Status 예제입니다.',
2093
+ code_props_usage: `
2094
+ import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader'
2095
+ import i18n from '@opsnow-common/opsnow-finops-common-i18n'
2096
+
2097
+ // 컬럼 정의
2098
+ const columnDefs = [
2099
+ { headerName: 'Make', field: 'make' },
2100
+ { headerName: 'Model', field: 'model' },
2101
+ { headerName: 'Price', field: 'price' },
2102
+ ]
2103
+
2104
+ const gridOptions = {
2105
+ animateRows: true,
2106
+ rowSelection: { mode: 'singleRow', checkboxes: false, enableClickSelection: true },
2107
+ tooltipShowDelay: 100,
2108
+ domLayout: 'autoHeight',
2109
+ suppressCellFocus: true,
2110
+ }
2111
+
2112
+ const { OpsnowCommonDataGrid } = useCommonComponents();
2113
+ const { CommonConst } = useGlobalContext()
2114
+ // errorStatus 상태를 관리
2115
+ const [errorStatus, setErrorStatus] = useState(CommonConst.GRID_STATUS.LOADING)
2116
+
2117
+ // 에러 상태 시뮬레이션을 위한 useEffect
2118
+ useEffect(() => {
2119
+ // 1초 후에 에러 상태로 설정
2120
+ const timeoutId = setTimeout(() => {
2121
+ setErrorStatus(CommonConst.GRID_STATUS.ERROR)
2122
+ }, 1000)
2123
+
2124
+ // 컴포넌트 언마운트 시 타임아웃 클리어
2125
+ return () => {
2126
+ clearTimeout(timeoutId)
2127
+ }
2128
+ }, [])
2129
+ `,
2130
+ code: `<OpsnowCommonDataGrid
2131
+ columnDefs={columnDefs}
2132
+ rowData={[]}
2133
+ status={errorStatus}
2134
+ gridOptions={gridOptions}
2135
+ textErrorTitle="데이터 로드 실패"
2136
+ textErrorDescription="데이터를 불러오는 중 오류가 발생했습니다."
2137
+ langCd={i18n.getLocale()}
2138
+ />`
2139
+ },
2140
+ {
2141
+ title: 'Long Text with autoHeight',
2142
+ description: 'Long Text with autoHeight (긴 텍스트 자동 높이 조절) 예제입니다.',
2143
+ code_props_usage: `
2144
+ import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader'
2145
+ import i18n from '@opsnow-common/opsnow-finops-common-i18n'
2146
+
2147
+ // Long Text용 컬럼 정의
2148
+ const columnDefs = [
2149
+ {
2150
+ headerName: 'ID',
2151
+ field: 'id',
2152
+ flex: 1,
2153
+ minWidth: 80
2154
+ },
2155
+ {
2156
+ headerName: 'Description',
2157
+ field: 'description',
2158
+ flex: 3, // 가장 넓은 비율
2159
+ minWidth: 300,
2160
+ suppressSizeToFit: true, // 자동 리사이즈 방지
2161
+ cellStyle: {
2162
+ 'align-items': 'center' // autoHeight 작동을 위해 필수
2163
+ }
2164
+ },
2165
+ {
2166
+ headerName: 'Status',
2167
+ field: 'status',
2168
+ flex: 1,
2169
+ minWidth: 120
2170
+ },
2171
+ ]
2172
+
2173
+ // Long Text용 행 데이터
2174
+ const rowData = [
2175
+ {
2176
+ id: 1,
2177
+ description: 'This is a very long description text that will wrap to multiple lines when the column width is not sufficient to display all content in a single line. This demonstrates the autoHeight feature.',
2178
+ status: 'Active'
2179
+ },
2180
+ {
2181
+ id: 2,
2182
+ description: 'Short text',
2183
+ status: 'Inactive'
2184
+ },
2185
+ {
2186
+ id: 3,
2187
+ description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.',
2188
+ status: 'Pending'
2189
+ },
2190
+ {
2191
+ id: 4,
2192
+ description: 'Another example of long text content that needs multiple lines',
2193
+ status: 'Active'
2194
+ },
2195
+ ]
2196
+
2197
+ const gridOptions = {
2198
+ animateRows: true,
2199
+ rowSelection: { mode: 'singleRow', checkboxes: false, enableClickSelection: true },
2200
+ tooltipShowDelay: 100,
2201
+ domLayout: 'autoHeight',
2202
+ suppressCellFocus: true,
2203
+ }
2204
+
2205
+ const { OpsnowCommonDataGrid } = useCommonComponents();
2206
+ const { CommonConst } = useGlobalContext()
2207
+ `,
2208
+ code: `<OpsnowCommonDataGrid
2209
+ columnDefs={columnDefs}
2210
+ rowData={rowData}
2211
+ status={CommonConst.GRID_STATUS.DATA_EXISTS}
2212
+ gridOptions={gridOptions}
2213
+ langCd={i18n.getLocale()}
2214
+ />`
2215
+ },
2086
2216
  ];
@@ -37,7 +37,7 @@ const columnDefsSchema = z.lazy(() => z.object({
37
37
  colId: z.string().optional().describe('컬럼 고유 ID'),
38
38
  groupId: z.string().optional().describe('컬럼 그룹 고유 ID'),
39
39
  width: z.number().optional().describe('컬럼 너비'),
40
- minWidth: z.number().optional().describe('컬럼 최소 너비'),
40
+ minWidth: z.number().describe('컬럼 최소 너비'),
41
41
  maxWidth: z.number().optional().describe('컬럼 최대 너비'),
42
42
  pinned: z.enum(['left', 'right']).optional().describe('컬럼 고정 위치'),
43
43
  type: z.array(z.enum([
@@ -126,7 +126,27 @@ export const DataGridSchema = z.object({
126
126
  columnDefs: z.array(columnDefsSchema).describe("ag-grid 컬럼 정의").min(1),
127
127
  defaultColDef: defaultColDefSchema.optional().describe('ag-grid 기본 컬럼 옵션'),
128
128
  rowData: z.array(z.record(z.any())).optional().describe('그리드에 표시할 데이터'),
129
- status: z.number().describe('그리드 상태값: 0-로딩, 1-데이터 있음, 9-에러'),
129
+ status: z.number().describe(`그리드 상태값: GRID.STATUS.LOADING(0), GRID.STATUS.DATA_EXISTS(1), GRID.STATUS.ERROR(9) 중 하나를 사용해야 합니다.
130
+
131
+ **필수 구현 패턴:**
132
+ 반드시 useState로 상태를 관리하고, useEffect 등을 사용하여 데이터 로딩 로직을 구현해야 합니다.
133
+ 사용자는 이 상태 제어 코드 안에 실제 비즈니스 로직(API 호출, 데이터 처리 등)을 추가할 수 있습니다.
134
+
135
+ 예제:
136
+ const [status, setStatus] = useState(CommonConst.GRID_STATUS.LOADING)
137
+ const [rowData, setRowData] = useState([])
138
+
139
+ useEffect(() => {
140
+ // 여기에 실제 비즈니스 로직을 추가합니다 (예: API 호출)
141
+ fetchData()
142
+ .then(data => {
143
+ setRowData(data)
144
+ setStatus(CommonConst.GRID_STATUS.DATA_EXISTS)
145
+ })
146
+ .catch(error => {
147
+ setStatus(CommonConst.GRID_STATUS.ERROR)
148
+ })
149
+ }, [])`),
130
150
  gridHeight: z.number().optional().describe('그리드 높이'),
131
151
  setClass: z.string().optional().describe('그리드 클래스명'),
132
152
  localRowClass: z.string().optional().describe('로컬 행 클래스명'),
@@ -141,7 +161,10 @@ export const DataGridSchema = z.object({
141
161
  searchTextNoData: z.string().optional().describe('검색 결과 없음 텍스트'),
142
162
  searchTextNoDataDescription: z.string().optional().describe('검색 결과 없음 설명'),
143
163
  pagingFromServer: z.boolean().optional().describe('서버 페이징 사용 여부'),
144
- pageSizeList: z.array(z.number()).optional().describe('페이지 사이즈 리스트'),
164
+ pageSizeList: z.array(z.object({
165
+ label: z.string().describe('페이지 사이즈 라벨'),
166
+ value: z.number().describe('페이지 사이즈 값')
167
+ })).optional().describe('페이지 사이즈 리스트 (예: [{ label: "5", value: 5 }, { label: "10", value: 10 }])'),
145
168
  placeholderText: z.string().optional().describe('플레이스홀더 텍스트'),
146
169
  usedRowClass: z.boolean().optional().describe('행 클래스 사용 여부 (셀 클릭 이벤트 사용 시 필수: true)'),
147
170
  usedSearch: z.boolean().optional().describe('검색창 사용 여부'),
@@ -182,20 +205,112 @@ export function createDataGridComponent() {
182
205
  **이 데이터 그리드 컴포넌트는 ag-grid를 기반으로 구현되었습니다.**
183
206
  **데이터 그리드 데이터, 컬럼 정의 등의 데이터가 제공되지 않을 경우 목업 데이터를 사용하세요.**
184
207
 
185
- **페이지네이션 사용법:**
186
- - 그리드는 내장 페이지네이션 기능을 제공합니다.
187
- - 별도의 Pagination 컴포넌트를 추가할 필요가 없습니다.
188
- - 페이지네이션을 사용하려면 다음 props를 설정하세요:
189
- pagination={true} - 페이지네이션 활성화
190
- paginationPageSize={10} - 페이지당
191
- pageSizeList={[5, 10, 20, 50]} - 페이지 크기 선택 옵션
192
- - 서버 사이드 페이징은 pagingFromServer={true}와 serverSideTotalPageSize를 사용하세요.
208
+ **중요: 긴 텍스트 컬럼 처리 (필수)**
209
+ 컬럼 값이 길어서 줄바꿈이 필요한 경우, 반드시 다음을 따라야 합니다:
210
+ 1. 모든 컬럼에 flex 속성 필수 (비율로 너비 분배, 예: flex: 1, flex: 3)
211
+ 2. 텍스트 컬럼에 suppressSizeToFit: true 필수
212
+ 3. 긴 텍스트 컬럼에 cellStyle: { 'align-items': 'center' } 필수
213
+ 4. gridOptions에 domLayout: 'autoHeight' 설정
214
+
215
+ 예시:
216
+ const columnDefs = [
217
+ { headerName: 'ID', field: 'id', flex: 1, minWidth: 80 },
218
+ {
219
+ headerName: 'Description',
220
+ field: 'description',
221
+ flex: 3,
222
+ minWidth: 300,
223
+ suppressSizeToFit: true,
224
+ cellStyle: { 'align-items': 'center' }
225
+ },
226
+ { headerName: 'Status', field: 'status', flex: 1, minWidth: 120 }
227
+ ];
193
228
 
194
229
  **import:**
195
230
  \`\`\`javascript
196
231
  import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader';
197
232
  const { OpsnowCommonDataGrid } = useCommonComponents();
198
- const { CommonConst } = useGlobalContext()
233
+ const { CommonConst } = useGlobalContext();
234
+ \`\`\`
235
+
236
+ **중요: 상태 관리 패턴 (필수 구현)**
237
+ 데이터 그리드를 구현할 때는 반드시 아래의 세 가지 상태(LOADING, DATA_EXISTS, ERROR)를 모두 처리하는 코드를 포함해야 합니다.
238
+
239
+ **절대 하지 말아야 할 것:**
240
+ - useState에 직접 데이터를 넣지 마세요: const [rowData] = useState([{...}]) ❌
241
+ - status를 바로 DATA_EXISTS로 설정하지 마세요: const [status] = useState(CommonConst.GRID_STATUS.DATA_EXISTS) ❌
242
+ - useEffect 없이 구현하지 마세요 ❌
243
+
244
+ **반드시 따라야 할 구현 패턴:**
245
+ 1. status는 반드시 CommonConst.GRID_STATUS.LOADING으로 시작
246
+ 2. rowData는 반드시 빈 배열 []로 시작
247
+ 3. useEffect를 반드시 사용하여 데이터 로딩 시뮬레이션
248
+ 4. .then()으로 성공 처리 → CommonConst.GRID_STATUS.DATA_EXISTS로 변경
249
+ 5. .catch()로 에러 처리 → CommonConst.GRID_STATUS.ERROR로 변경
250
+ 6. OpsnowCommonDataGrid에 textErrorTitle, textErrorDescription 속성 반드시 포함
251
+
252
+ 사용자는 생성된 코드의 useEffect 내부에 실제 비즈니스 로직(API 호출, 데이터 변환 등)을 추가할 수 있습니다.
253
+
254
+ **기본 패턴 예제 (정확히 이 구조를 따라야 함):**
255
+ \`\`\`javascript
256
+ // ✅ 올바른 방법: LOADING으로 시작, 빈 배열로 시작
257
+ const [status, setStatus] = useState(CommonConst.GRID_STATUS.LOADING);
258
+ const [rowData, setRowData] = useState([]);
259
+
260
+ // ✅ 올바른 방법: useEffect에서 데이터 로딩
261
+ useEffect(() => {
262
+ // 사용자가 여기에 실제 API 호출 등 비즈니스 로직을 추가합니다
263
+ const fetchData = async () => {
264
+ try {
265
+ // 실제로는 여기에 API 호출을 넣습니다
266
+ // 예: const response = await fetch('/api/data');
267
+ // const data = await response.json();
268
+
269
+ // 데모를 위한 시뮬레이션
270
+ await new Promise(resolve => setTimeout(resolve, 1000));
271
+
272
+ const mockData = [
273
+ { make: 'Toyota', model: 'Celica', price: 35000 },
274
+ { make: 'Ford', model: 'Mondeo', price: 32000 }
275
+ ];
276
+
277
+ setRowData(mockData);
278
+ setStatus(CommonConst.GRID_STATUS.DATA_EXISTS);
279
+ } catch (error) {
280
+ console.error('Error loading data:', error);
281
+ setStatus(CommonConst.GRID_STATUS.ERROR);
282
+ }
283
+ };
284
+
285
+ fetchData();
286
+ }, []);
287
+
288
+ // gridOptions 정의 (권장)
289
+ const gridOptions = {
290
+ animateRows: true,
291
+ rowSelection: { mode: 'singleRow', checkboxes: false, enableClickSelection: true },
292
+ tooltipShowDelay: 100,
293
+ domLayout: 'autoHeight',
294
+ suppressCellFocus: true,
295
+ };
296
+
297
+ // ✅ 올바른 방법: 에러 관련 속성 포함
298
+ <OpsnowCommonDataGrid
299
+ columnDefs={columnDefs}
300
+ rowData={rowData}
301
+ status={status}
302
+ gridOptions={gridOptions}
303
+ pagination={true}
304
+ paginationPageSize={5}
305
+ pageSizeList={[
306
+ { label: '5', value: 5 },
307
+ { label: '10', value: 10 },
308
+ { label: '20', value: 20 }
309
+ ]}
310
+ textErrorTitle="데이터 로드 실패"
311
+ textErrorDescription="데이터를 불러오는 중 오류가 발생했습니다."
312
+ langCd={i18n.getLocale()}
313
+ />
199
314
  \`\`\``,
200
315
  parameters: DataGridSchema,
201
316
  handler: async (args) => {
@@ -51,13 +51,6 @@ export function createPaginationComponent() {
51
51
  name: "createPagination",
52
52
  description: `페이지네이션 컴포넌트 - 페이지 이동 및 크기 조절
53
53
 
54
- **중요: OpsnowCommonDataGrid(데이터 그리드)와 함께 사용하는 경우**
55
- - OpsnowCommonDataGrid는 내장 페이지네이션 기능을 제공합니다.
56
- - 데이터 그리드에서 페이지네이션을 사용하려면 이 툴을 사용하지 말고 createDataGrid 툴을 사용하세요.
57
-
58
- **이 툴을 사용해야 하는 경우**
59
- - 데이터 그리드가 아닌 일반 목록이나 카드 뷰에서 페이지네이션이 필요한 경우에만 사용하세요.
60
-
61
54
  **import**:
62
55
  \`\`\`jsx
63
56
  import { useCommonComponents } from '@opsnow-common/opsnow-finops-common-ui-loader'
package/build/index.js CHANGED
@@ -26,6 +26,56 @@ import { createCommonExamplesComponent } from "./components/opsnow-common-exampl
26
26
  const server = new McpServer({
27
27
  name: "opsnow-mcp-common-ui-server",
28
28
  version: "1.0.0"
29
+ }, {
30
+ instructions: `OpsNow UI Components Usage Guidelines:
31
+
32
+ IMPORTANT: All components require React 18.x or higher environment.
33
+ Always include required import statements and i18n configuration when needed.
34
+
35
+ **CRITICAL: OpsnowCommonDataGrid Usage Rules**
36
+
37
+ Before implementing OpsnowCommonDataGrid, you MUST use getUIExamples tool with 'DataGrid' parameter first!
38
+
39
+ 1. Grid Top Search/Button Area - You MUST use children or searchAddon slots:
40
+
41
+ [CORRECT] Using children slot:
42
+ <OpsnowCommonDataGrid usedSearch={true}>
43
+ <OpsnowCommonButton label="Add" iconName="Plus" />
44
+ </OpsnowCommonDataGrid>
45
+
46
+ [CORRECT] Using searchAddon slot:
47
+ <OpsnowCommonDataGrid
48
+ usedSearch={true}
49
+ searchAddon={<OpsnowCommonDatePicker />}
50
+ />
51
+
52
+ [FORBIDDEN] DO NOT create separate Stack/Box outside the grid:
53
+ <Stack direction="row"> <- DO NOT DO THIS!
54
+ <OpsnowCommonButton label="Add" />
55
+ </Stack>
56
+ <OpsnowCommonDataGrid usedSearch={true} />
57
+
58
+ Reference example: "Insert Button Inside the Common Grid Search Section"
59
+
60
+ 2. Grid Bottom Pagination - You MUST use built-in pagination prop:
61
+
62
+ [CORRECT] Using built-in pagination:
63
+ <OpsnowCommonDataGrid
64
+ pagination={true}
65
+ paginationPageSize={10}
66
+ pageSizeList={[
67
+ { label: '10', value: 10 },
68
+ { label: '20', value: 20 }
69
+ ]}
70
+ />
71
+
72
+ [FORBIDDEN] DO NOT use OpsnowCommonPagination component separately:
73
+ <OpsnowCommonDataGrid />
74
+ <OpsnowCommonPagination /> <- DO NOT DO THIS!
75
+
76
+ Reference example: "Search + Pagination"
77
+
78
+ WARNING: Violating these rules will cause the UI to malfunction.`
29
79
  });
30
80
  // 컴포넌트들 등록
31
81
  const componentFactories = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opsnow-mcp/opsnow-mcp-common-ui-server",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "bin": {