@opsnow-mcp/opsnow-mcp-common-ui-server 1.0.8 → 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.
@@ -1885,4 +1885,332 @@ export const DataGridExamples = [
1885
1885
  <button onClick={setCheckBox}>set check box</button>
1886
1886
  </OpsnowCommonDataGrid>`
1887
1887
  },
1888
+ {
1889
+ title: 'Column Group - Basic',
1890
+ description: 'children 속성을 사용한 기본 컬럼 그룹 예제입니다.',
1891
+ code_props_usage: `
1892
+ import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader'
1893
+ import i18n from '@opsnow-common/opsnow-finops-common-i18n'
1894
+
1895
+ // 컬럼 그룹 정의 - children을 사용한 예제
1896
+ const columnDefs = [
1897
+ {
1898
+ groupId: 'vehicleGroup',
1899
+ headerName: 'Vehicle Info',
1900
+ children: [
1901
+ { headerName: 'Make', field: 'make' },
1902
+ { headerName: 'Model', field: 'model' },
1903
+ ],
1904
+ },
1905
+ {
1906
+ groupId: 'financialGroup',
1907
+ headerName: 'Financial Info',
1908
+ children: [
1909
+ {
1910
+ headerName: 'Price',
1911
+ field: 'price',
1912
+ valueFormatter: params => params.value ? \`$\${params.value.toLocaleString()}\` : ''
1913
+ },
1914
+ {
1915
+ headerName: 'Tax',
1916
+ field: 'tax',
1917
+ valueFormatter: params => params.value ? \`$\${params.value.toLocaleString()}\` : ''
1918
+ },
1919
+ ],
1920
+ },
1921
+ {
1922
+ groupId: 'salesGroup',
1923
+ headerName: 'Sales Info',
1924
+ children: [
1925
+ { headerName: 'Year', field: 'year' },
1926
+ { headerName: 'Country', field: 'country' },
1927
+ ],
1928
+ },
1929
+ ]
1930
+
1931
+ // 초기 행 데이터
1932
+ const initialRowData = [
1933
+ { make: 'Toyota', model: 'Celica', price: 35000, tax: 3500, year: 2020, country: 'Japan' },
1934
+ { make: 'Ford', model: 'Mondeo', price: 32000, tax: 3200, year: 2019, country: 'USA' },
1935
+ { make: 'Porsche', model: 'Boxter', price: 72000, tax: 7200, year: 2021, country: 'Germany' },
1936
+ { make: 'BMW', model: 'M3', price: 65000, tax: 6500, year: 2020, country: 'Germany' },
1937
+ { make: 'Honda', model: 'Civic', price: 28000, tax: 2800, year: 2019, country: 'Japan' },
1938
+ { make: 'Tesla', model: 'Model S', price: 95000, tax: 9500, year: 2022, country: 'USA' },
1939
+ { make: 'Audi', model: 'A4', price: 45000, tax: 4500, year: 2020, country: 'Germany' },
1940
+ { make: 'Mercedes', model: 'C-Class', price: 55000, tax: 5500, year: 2021, country: 'Germany' },
1941
+ { make: 'Nissan', model: 'Altima', price: 30000, tax: 3000, year: 2019, country: 'Japan' },
1942
+ { make: 'Chevrolet', model: 'Malibu', price: 33000, tax: 3300, year: 2020, country: 'USA' },
1943
+ ]
1944
+
1945
+ const gridOptions = {
1946
+ animateRows: true,
1947
+ rowSelection: { mode: 'singleRow', checkboxes: false, enableClickSelection: true },
1948
+ tooltipShowDelay: 100,
1949
+ domLayout: 'autoHeight',
1950
+ suppressCellFocus: true,
1951
+ }
1952
+
1953
+ const { OpsnowCommonDataGrid } = useCommonComponents();
1954
+ const { CommonConst } = useGlobalContext()
1955
+ // rowData와 status 상태를 관리
1956
+ const [rowData, setRowData] = useState([]) // 초기에는 빈 배열로 설정
1957
+ const [status, setStatus] = useState(CommonConst.GRID_STATUS.LOADING) // 초기에는 LOADING 상태
1958
+
1959
+ // 데이터 지연 설정을 위한 useEffect
1960
+ useEffect(() => {
1961
+ // 1초 후에 데이터를 설정
1962
+ const timeoutId = setTimeout(() => {
1963
+ setRowData(initialRowData)
1964
+ setStatus(CommonConst.GRID_STATUS.DATA_EXISTS)
1965
+ }, 1000)
1966
+
1967
+ // 컴포넌트 언마운트 시 타임아웃 클리어
1968
+ return () => {
1969
+ clearTimeout(timeoutId)
1970
+ }
1971
+ }, [])
1972
+ `,
1973
+ code: `<OpsnowCommonDataGrid
1974
+ columnDefs={columnDefs}
1975
+ rowData={rowData}
1976
+ status={status}
1977
+ gridOptions={gridOptions}
1978
+ usedSearch={true}
1979
+ pagination={true}
1980
+ paginationPageSize={5}
1981
+ pageSizeList={[
1982
+ { label: '5', value: 5 },
1983
+ { label: '10', value: 10 },
1984
+ { label: '20', value: 20 },
1985
+ ]}
1986
+ langCd={i18n.getLocale()}
1987
+ />`
1988
+ },
1989
+ {
1990
+ title: 'Column Group - Nested',
1991
+ description: '다층 구조의 중첩된 컬럼 그룹 예제입니다.',
1992
+ code_props_usage: `
1993
+ import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader'
1994
+ import i18n from '@opsnow-common/opsnow-finops-common-i18n'
1995
+
1996
+ // 중첩된 컬럼 그룹 정의
1997
+ const nestedColumnDefs = [
1998
+ {
1999
+ groupId: 'vehicleMainGroup',
2000
+ headerName: 'Vehicle',
2001
+ children: [
2002
+ {
2003
+ groupId: 'vehicleBasicGroup',
2004
+ headerName: 'Basic Info',
2005
+ children: [
2006
+ { headerName: 'Make', field: 'make' },
2007
+ { headerName: 'Model', field: 'model' },
2008
+ ],
2009
+ },
2010
+ {
2011
+ groupId: 'vehicleDetailsGroup',
2012
+ headerName: 'Details',
2013
+ children: [
2014
+ { headerName: 'Year', field: 'year' },
2015
+ { headerName: 'Country', field: 'country' },
2016
+ ],
2017
+ },
2018
+ ],
2019
+ },
2020
+ {
2021
+ groupId: 'financialMainGroup',
2022
+ headerName: 'Financial',
2023
+ children: [
2024
+ {
2025
+ headerName: 'Price',
2026
+ field: 'price',
2027
+ valueFormatter: params => params.value ? \`$\${params.value.toLocaleString()}\` : ''
2028
+ },
2029
+ {
2030
+ headerName: 'Tax',
2031
+ field: 'tax',
2032
+ valueFormatter: params => params.value ? \`$\${params.value.toLocaleString()}\` : ''
2033
+ },
2034
+ ],
2035
+ },
2036
+ ]
2037
+
2038
+ // 초기 행 데이터
2039
+ const initialRowData = [
2040
+ { make: 'Toyota', model: 'Celica', price: 35000, tax: 3500, year: 2020, country: 'Japan' },
2041
+ { make: 'Ford', model: 'Mondeo', price: 32000, tax: 3200, year: 2019, country: 'USA' },
2042
+ { make: 'Porsche', model: 'Boxter', price: 72000, tax: 7200, year: 2021, country: 'Germany' },
2043
+ { make: 'BMW', model: 'M3', price: 65000, tax: 6500, year: 2020, country: 'Germany' },
2044
+ { make: 'Honda', model: 'Civic', price: 28000, tax: 2800, year: 2019, country: 'Japan' },
2045
+ { make: 'Tesla', model: 'Model S', price: 95000, tax: 9500, year: 2022, country: 'USA' },
2046
+ { make: 'Audi', model: 'A4', price: 45000, tax: 4500, year: 2020, country: 'Germany' },
2047
+ { make: 'Mercedes', model: 'C-Class', price: 55000, tax: 5500, year: 2021, country: 'Germany' },
2048
+ { make: 'Nissan', model: 'Altima', price: 30000, tax: 3000, year: 2019, country: 'Japan' },
2049
+ { make: 'Chevrolet', model: 'Malibu', price: 33000, tax: 3300, year: 2020, country: 'USA' },
2050
+ ]
2051
+
2052
+ const gridOptions = {
2053
+ animateRows: true,
2054
+ rowSelection: { mode: 'singleRow', checkboxes: false, enableClickSelection: true },
2055
+ tooltipShowDelay: 100,
2056
+ domLayout: 'autoHeight',
2057
+ suppressCellFocus: true,
2058
+ }
2059
+
2060
+ const { OpsnowCommonDataGrid } = useCommonComponents();
2061
+ const { CommonConst } = useGlobalContext()
2062
+ // rowData와 status 상태를 관리
2063
+ const [rowData, setRowData] = useState([]) // 초기에는 빈 배열로 설정
2064
+ const [status, setStatus] = useState(CommonConst.GRID_STATUS.LOADING) // 초기에는 LOADING 상태
2065
+
2066
+ // 데이터 지연 설정을 위한 useEffect
2067
+ useEffect(() => {
2068
+ // 1초 후에 데이터를 설정
2069
+ const timeoutId = setTimeout(() => {
2070
+ setRowData(initialRowData)
2071
+ setStatus(CommonConst.GRID_STATUS.DATA_EXISTS)
2072
+ }, 1000)
2073
+
2074
+ // 컴포넌트 언마운트 시 타임아웃 클리어
2075
+ return () => {
2076
+ clearTimeout(timeoutId)
2077
+ }
2078
+ }, [])
2079
+ `,
2080
+ code: `<OpsnowCommonDataGrid
2081
+ key={status}
2082
+ columnDefs={nestedColumnDefs}
2083
+ rowData={rowData}
2084
+ status={status}
2085
+ gridOptions={gridOptions}
2086
+ usedSearch={true}
2087
+ langCd={i18n.getLocale()}
2088
+ />`
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
+ },
1888
2216
  ];
@@ -31,12 +31,13 @@ const gridOptionsSchema = z.object({
31
31
  getRowId: z.string().optional().describe('행 ID 반환 함수(stringified)'),
32
32
  suppressMenuHide: z.boolean().optional().describe('메뉴 숨김 억제'),
33
33
  });
34
- const columnDefsSchema = z.object({
34
+ const columnDefsSchema = z.lazy(() => z.object({
35
35
  headerName: z.string().optional().describe('컬럼 헤더명'),
36
36
  field: z.string().optional().describe('컬럼 데이터 필드명'),
37
37
  colId: z.string().optional().describe('컬럼 고유 ID'),
38
+ groupId: z.string().optional().describe('컬럼 그룹 고유 ID'),
38
39
  width: z.number().optional().describe('컬럼 너비'),
39
- minWidth: z.number().optional().describe('컬럼 최소 너비'),
40
+ minWidth: z.number().describe('컬럼 최소 너비'),
40
41
  maxWidth: z.number().optional().describe('컬럼 최대 너비'),
41
42
  pinned: z.enum(['left', 'right']).optional().describe('컬럼 고정 위치'),
42
43
  type: z.array(z.enum([
@@ -101,7 +102,8 @@ const columnDefsSchema = z.object({
101
102
  filterParams: z.any().optional().describe('필터 파라미터'),
102
103
  cellRendererSelector: z.string().optional().describe('셀 렌더러 선택 함수(stringified)'),
103
104
  colSpan: z.string().optional().describe('컬럼 병합 함수(stringified)'),
104
- });
105
+ children: z.array(z.lazy(() => columnDefsSchema)).optional().describe('하위 컬럼 정의 배열 (컬럼 그룹화)'),
106
+ }));
105
107
  const defaultColDefSchema = z.object({
106
108
  wrapText: z.boolean().optional().describe('텍스트 줄바꿈'),
107
109
  autoHeight: z.boolean().optional().describe('자동 높이'),
@@ -124,7 +126,27 @@ export const DataGridSchema = z.object({
124
126
  columnDefs: z.array(columnDefsSchema).describe("ag-grid 컬럼 정의").min(1),
125
127
  defaultColDef: defaultColDefSchema.optional().describe('ag-grid 기본 컬럼 옵션'),
126
128
  rowData: z.array(z.record(z.any())).optional().describe('그리드에 표시할 데이터'),
127
- 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
+ }, [])`),
128
150
  gridHeight: z.number().optional().describe('그리드 높이'),
129
151
  setClass: z.string().optional().describe('그리드 클래스명'),
130
152
  localRowClass: z.string().optional().describe('로컬 행 클래스명'),
@@ -139,7 +161,10 @@ export const DataGridSchema = z.object({
139
161
  searchTextNoData: z.string().optional().describe('검색 결과 없음 텍스트'),
140
162
  searchTextNoDataDescription: z.string().optional().describe('검색 결과 없음 설명'),
141
163
  pagingFromServer: z.boolean().optional().describe('서버 페이징 사용 여부'),
142
- 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 }])'),
143
168
  placeholderText: z.string().optional().describe('플레이스홀더 텍스트'),
144
169
  usedRowClass: z.boolean().optional().describe('행 클래스 사용 여부 (셀 클릭 이벤트 사용 시 필수: true)'),
145
170
  usedSearch: z.boolean().optional().describe('검색창 사용 여부'),
@@ -179,12 +204,113 @@ export function createDataGridComponent() {
179
204
 
180
205
  **이 데이터 그리드 컴포넌트는 ag-grid를 기반으로 구현되었습니다.**
181
206
  **데이터 그리드 데이터, 컬럼 정의 등의 데이터가 제공되지 않을 경우 목업 데이터를 사용하세요.**
182
-
207
+
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
+ ];
228
+
183
229
  **import:**
184
230
  \`\`\`javascript
185
231
  import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader';
186
232
  const { OpsnowCommonDataGrid } = useCommonComponents();
187
- 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
+ />
188
314
  \`\`\``,
189
315
  parameters: DataGridSchema,
190
316
  handler: async (args) => {
@@ -50,6 +50,7 @@ export function createPaginationComponent() {
50
50
  {
51
51
  name: "createPagination",
52
52
  description: `페이지네이션 컴포넌트 - 페이지 이동 및 크기 조절
53
+
53
54
  **import**:
54
55
  \`\`\`jsx
55
56
  import { useCommonComponents } from '@opsnow-common/opsnow-finops-common-ui-loader'
package/build/index.js CHANGED
@@ -25,8 +25,57 @@ import { createCommonExamplesComponent } from "./components/opsnow-common-exampl
25
25
  // MCP 서버 생성
26
26
  const server = new McpServer({
27
27
  name: "opsnow-mcp-common-ui-server",
28
- version: "1.0.0",
29
- description: "이 도구 서버는 MUI(Material-UI) 기반의 UI 컴포넌트를 제공합니다. 이 컴포넌트들을 사용하는 코드를 생성할 때는, 일관된 디자인을 위해 화면 레이아웃과 스타일링에 MUI의 컴포넌트와 스타일링 유틸리티(예: '@mui/material', '@mui/system' 등)를 적극적으로 활용해야 합니다.",
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.`
30
79
  });
31
80
  // 컴포넌트들 등록
32
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.8",
3
+ "version": "1.0.10",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "bin": {