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

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.
@@ -502,7 +502,7 @@ export const BarChartExamples = [
502
502
  width: 'p50',
503
503
  hover: {
504
504
  enabled: true,
505
- grouped: true
505
+ : true
506
506
  }
507
507
  },
508
508
  tooltip: {
@@ -2109,6 +2109,81 @@ export const LineChartExamples = [
2109
2109
  chartData={chartData}
2110
2110
  />`
2111
2111
  },
2112
+ {
2113
+ title: '라인 차트 - Bullet Label (데이터 포인트에 값 표시)',
2114
+ description: '라인 차트의 각 데이터 포인트 위에 값을 라벨로 표시하는 bullet label 예제입니다. format, prefix, suffix를 사용하여 값 형식을 지정할 수 있습니다.',
2115
+ code_props_usage: `
2116
+ const chartId = 'line-chart-bullet-label-${generateUniqueGeneralId()}'
2117
+ const chartRef = useRef(null)
2118
+ const [chartProps, setChartProps] = useState({
2119
+ chart: {
2120
+ paddingTop: 30,
2121
+ paddingBottom: 30
2122
+ },
2123
+ xAxis: {
2124
+ type: 'date',
2125
+ dateFormats: [
2126
+ { type: 'day', dateFormat: 'MM-dd' },
2127
+ { type: 'month', dateFormat: 'yy-MM' }
2128
+ ],
2129
+ baseInterval: { timeUnit: 'month', count: 1 },
2130
+ gridHidden: true
2131
+ },
2132
+ yAxis: {
2133
+ type: 'value',
2134
+ extraMax: 0.15,
2135
+ min: 0,
2136
+ numberFormat: '$#,###'
2137
+ },
2138
+ series: {
2139
+ valueXField: 'date',
2140
+ dataProcessor: {
2141
+ dateFields: ['date'],
2142
+ dateFormat: 'yyyy-MM-dd'
2143
+ },
2144
+ bullet: {
2145
+ type: 'label', // 'label' 타입으로 설정
2146
+ locationX: 0.5, // X축 위치 (0~1, 0.5 = 중앙)
2147
+ locationY: 1, // Y축 위치 (0~1, 1 = 상단)
2148
+ label: {
2149
+ dy: -15, // Y축 오프셋 (음수: 위로 이동)
2150
+ format: '#,###', // 숫자 포맷
2151
+ prefix: '$', // 접두사
2152
+ fontSize: 9
2153
+ }
2154
+ }
2155
+ },
2156
+ legend: { useExtension: false }
2157
+ })
2158
+ const [chartCategory, setChartCategory] = useState(['cost1', 'cost2'])
2159
+ const [chartData, setChartData] = useState([
2160
+ { date: '2024-10-01', cost1: 70000, cost2: 8000 },
2161
+ { date: '2024-11-01', cost1: 85000, cost2: 10000 },
2162
+ { date: '2024-12-01', cost1: 170000, cost2: 15000 },
2163
+ { date: '2025-01-01', cost1: 165000, cost2: 14000 },
2164
+ { date: '2025-02-01', cost1: 95000, cost2: 10000 },
2165
+ { date: '2025-03-01', cost1: 115000, cost2: 12000 },
2166
+ { date: '2025-04-01', cost1: 140000, cost2: 13000 },
2167
+ { date: '2025-05-01', cost1: 270000, cost2: 18000 },
2168
+ { date: '2025-06-01', cost1: 135000, cost2: 13500 },
2169
+ { date: '2025-07-01', cost1: 140000, cost2: 14000 },
2170
+ { date: '2025-08-01', cost1: 135000, cost2: 13800 },
2171
+ { date: '2025-09-01', cost1: 159857, cost2: 14334 }
2172
+ ])
2173
+ const chartCategoryLocaleMapping = [
2174
+ { name: 'cost1', value: '계정 1 비용' },
2175
+ { name: 'cost2', value: '계정 2 비용' }
2176
+ ]
2177
+ `,
2178
+ code: `<OpsnowCommonLineChart
2179
+ chartId={chartId}
2180
+ chartRef={chartRef}
2181
+ chartProps={chartProps}
2182
+ chartCategory={chartCategory}
2183
+ chartData={chartData}
2184
+ chartCategoryLocaleMapping={chartCategoryLocaleMapping}
2185
+ />`
2186
+ },
2112
2187
  ];
2113
2188
  export const StackChartExamples = [
2114
2189
  {
@@ -5980,4 +6055,331 @@ export const XyMultiChartExamples = [
5980
6055
  chartUserDefinedFunc={udf()}
5981
6056
  />`
5982
6057
  },
6058
+ {
6059
+ title: 'XY 멀티 차트 - Bullet Label (Line + Stack)',
6060
+ description: 'XY 멀티 차트에서 Line과 Stack 시리즈 모두에 bullet label을 적용하여 데이터 포인트에 값을 표시하는 예제입니다.',
6061
+ code_props_usage: `
6062
+ const chartId = 'xy-multi-bullet-label-${generateUniqueGeneralId()}'
6063
+ const chartRef = useRef(null)
6064
+ const [chartProps, setChartProps] = useState({
6065
+ chart: {
6066
+ paddingTop: 30
6067
+ },
6068
+ xAxis: {
6069
+ type: 'date',
6070
+ dateFormats: [
6071
+ { type: 'day', dateFormat: 'MM-dd' },
6072
+ { type: 'month', dateFormat: 'yy-MM' }
6073
+ ],
6074
+ baseInterval: { timeUnit: 'month', count: 1 },
6075
+ gridHidden: true
6076
+ },
6077
+ yAxis: {
6078
+ type: 'value',
6079
+ extraMax: 0.15,
6080
+ min: 0,
6081
+ numberFormat: '$#,###'
6082
+ },
6083
+ series: {
6084
+ valueXField: 'date',
6085
+ dataProcessor: {
6086
+ dateFields: ['date'],
6087
+ dateFormat: 'yyyy-MM-dd'
6088
+ },
6089
+ seriesTypes: [
6090
+ {
6091
+ type: 'line',
6092
+ order: 'front',
6093
+ categoryGroupName: 'cost_line',
6094
+ bullet: {
6095
+ type: 'label', // 라벨 타입 bullet
6096
+ locationX: 0.5,
6097
+ locationY: 1,
6098
+ label: {
6099
+ dy: -10, // 위로 이동
6100
+ format: '#,###', // 숫자 포맷
6101
+ prefix: '$', // 달러 기호 접두사
6102
+ fontSize: 9
6103
+ }
6104
+ }
6105
+ },
6106
+ {
6107
+ type: 'stack',
6108
+ categoryGroupName: 'cost_stack',
6109
+ bullet: {
6110
+ type: 'label',
6111
+ locationX: 0.5,
6112
+ locationY: 1,
6113
+ label: {
6114
+ dy: -10,
6115
+ format: '#,###',
6116
+ prefix: '$',
6117
+ fontSize: 9
6118
+ }
6119
+ }
6120
+ }
6121
+ ],
6122
+ tooltip: {
6123
+ type: 'CG',
6124
+ header: { name: '{category}' },
6125
+ body: {
6126
+ name: '{name}',
6127
+ value: '\${valueY.formatNumber("#,###")}',
6128
+ useMarker: true
6129
+ }
6130
+ }
6131
+ },
6132
+ legend: { useExtension: false }
6133
+ })
6134
+ const [chartData, setChartData] = useState([
6135
+ { date: '2024-10-01', totalCost: 79580, cloudCost: 50000, onpremCost: 29580 },
6136
+ { date: '2024-11-01', totalCost: 95812, cloudCost: 60000, onpremCost: 35812 },
6137
+ { date: '2024-12-01', totalCost: 182965, cloudCost: 120000, onpremCost: 62965 },
6138
+ { date: '2025-01-01', totalCost: 178695, cloudCost: 115000, onpremCost: 63695 },
6139
+ { date: '2025-02-01', totalCost: 103273, cloudCost: 70000, onpremCost: 33273 },
6140
+ { date: '2025-03-01', totalCost: 122976, cloudCost: 82000, onpremCost: 40976 },
6141
+ { date: '2025-04-01', totalCost: 151876, cloudCost: 100000, onpremCost: 51876 },
6142
+ { date: '2025-05-01', totalCost: 288608, cloudCost: 190000, onpremCost: 98608 },
6143
+ { date: '2025-06-01', totalCost: 146040, cloudCost: 95000, onpremCost: 51040 },
6144
+ { date: '2025-07-01', totalCost: 151794, cloudCost: 100000, onpremCost: 51794 },
6145
+ { date: '2025-08-01', totalCost: 147177, cloudCost: 97000, onpremCost: 50177 },
6146
+ { date: '2025-09-01', totalCost: 196047, cloudCost: 130000, onpremCost: 66047 }
6147
+ ])
6148
+ const [chartCategory, setChartCategory] = useState([
6149
+ { name: 'cost_line', categories: ['totalCost'] },
6150
+ { name: 'cost_stack', categories: ['cloudCost', 'onpremCost'] }
6151
+ ])
6152
+ const chartCategoryLocaleMapping = [
6153
+ { name: 'totalCost', value: '총 비용' },
6154
+ { name: 'cloudCost', value: '클라우드 비용' },
6155
+ { name: 'onpremCost', value: '온프레미스 비용' }
6156
+ ]
6157
+ `,
6158
+ code: `<OpsnowCommonXyMultiChart
6159
+ chartId={chartId}
6160
+ chartRef={chartRef}
6161
+ chartProps={chartProps}
6162
+ chartCategory={chartCategory}
6163
+ chartData={chartData}
6164
+ chartCategoryLocaleMapping={chartCategoryLocaleMapping}
6165
+ />`
6166
+ },
6167
+ {
6168
+ title: 'XY 멀티 차트 - Bullet Label (Dual Axis: Bar + Line)',
6169
+ description: 'Dual Axis(Y축 2개) 차트에서 Bar와 Line 시리즈에 각각 다른 bullet label을 적용하는 예제입니다. 비용(Bar)에는 달러 기호, 증감률(Line)에는 % 기호를 사용합니다.',
6170
+ code_props_usage: `
6171
+ const chartId = 'xy-multi-dual-axis-${generateUniqueGeneralId()}'
6172
+ const chartRef = useRef(null)
6173
+ const [chartProps, setChartProps] = useState({
6174
+ chart: {
6175
+ paddingTop: 30,
6176
+ paddingRight: 50
6177
+ },
6178
+ xAxis: {
6179
+ type: 'date',
6180
+ dateFormats: [
6181
+ { type: 'day', dateFormat: 'MM-dd' },
6182
+ { type: 'month', dateFormat: 'MMM\\nyyyy' }
6183
+ ],
6184
+ baseInterval: { timeUnit: 'month', count: 1 },
6185
+ gridHidden: true
6186
+ },
6187
+ yAxis: {
6188
+ type: 'value',
6189
+ numberFormat: "'$'#,###",
6190
+ extraMax: 0.15,
6191
+ min: 0
6192
+ },
6193
+ yAxis2: {
6194
+ type: 'value',
6195
+ numberFormat: "#'%'",
6196
+ opposite: true,
6197
+ gridHidden: true
6198
+ },
6199
+ series: {
6200
+ valueXField: 'date',
6201
+ dataProcessor: {
6202
+ dateFields: ['date'],
6203
+ dateFormat: 'yyyy-MM-dd'
6204
+ },
6205
+ seriesTypes: [
6206
+ {
6207
+ type: 'bar',
6208
+ categoryGroupName: 'bar_group',
6209
+ bullet: {
6210
+ type: 'label',
6211
+ locationX: 0.5,
6212
+ locationY: 1,
6213
+ label: {
6214
+ dy: -5,
6215
+ format: '#,###',
6216
+ prefix: '$', // 비용에 달러 기호
6217
+ fontSize: 9
6218
+ }
6219
+ }
6220
+ },
6221
+ {
6222
+ type: 'line',
6223
+ order: 'front',
6224
+ categoryGroupName: 'line_group',
6225
+ yAxis: 'yAxis2', // 두 번째 Y축 사용
6226
+ bullet: {
6227
+ type: 'label',
6228
+ locationX: 0.5,
6229
+ locationY: 1,
6230
+ label: {
6231
+ dy: -10,
6232
+ format: '#.#',
6233
+ suffix: '%', // 증감률에 % 기호
6234
+ fontSize: 9
6235
+ }
6236
+ }
6237
+ }
6238
+ ],
6239
+ tooltip: {
6240
+ type: 'CG',
6241
+ header: { name: '{valueX.formatDate("yyyy년 M월")}' },
6242
+ body: {
6243
+ name: '{name}',
6244
+ value: '{valueY}',
6245
+ useMarker: true
6246
+ }
6247
+ }
6248
+ },
6249
+ legend: { useExtension: false }
6250
+ })
6251
+ const [chartData, setChartData] = useState([
6252
+ { date: '2024-10-01', cost: 11255, changeRate: null },
6253
+ { date: '2024-11-01', cost: 18464, changeRate: 64.1 },
6254
+ { date: '2024-12-01', cost: 17335, changeRate: -6.1 },
6255
+ { date: '2025-01-01', cost: 18731, changeRate: 8.1 },
6256
+ { date: '2025-02-01', cost: 20358, changeRate: 8.7 },
6257
+ { date: '2025-03-01', cost: 27291, changeRate: 34.1 },
6258
+ { date: '2025-04-01', cost: 40417, changeRate: 48.1 },
6259
+ { date: '2025-05-01', cost: 39887, changeRate: -1.3 },
6260
+ { date: '2025-06-01', cost: 41529, changeRate: 4.1 },
6261
+ { date: '2025-07-01', cost: 49871, changeRate: 20.1 },
6262
+ { date: '2025-08-01', cost: 50659, changeRate: 1.6 },
6263
+ { date: '2025-09-01', cost: 58388, changeRate: 15.3 }
6264
+ ])
6265
+ const [chartCategory, setChartCategory] = useState([
6266
+ { name: 'bar_group', categories: ['cost'] },
6267
+ { name: 'line_group', categories: ['changeRate'] }
6268
+ ])
6269
+ const chartCategoryLocaleMapping = [
6270
+ { name: 'cost', value: 'Cost' },
6271
+ { name: 'changeRate', value: '증감률' }
6272
+ ]
6273
+ const chartCustomCategory = [
6274
+ { name: 'cost', color: '#C8A2C8' },
6275
+ { name: 'changeRate', color: '#2E4A62' }
6276
+ ]
6277
+ `,
6278
+ code: `<OpsnowCommonXyMultiChart
6279
+ chartId={chartId}
6280
+ chartRef={chartRef}
6281
+ chartProps={chartProps}
6282
+ chartCategory={chartCategory}
6283
+ chartData={chartData}
6284
+ chartCategoryLocaleMapping={chartCategoryLocaleMapping}
6285
+ chartCustomCategory={chartCustomCategory}
6286
+ />`
6287
+ },
6288
+ {
6289
+ title: 'XY 멀티 차트 - Bullet Label (Grouped Bar)',
6290
+ description: 'Grouped Bar 차트에서 bullet label을 사용하여 각 바 위에 값을 표시하는 예제입니다. text 속성으로 amCharts5 포맷 문자열을 직접 사용할 수 있습니다.',
6291
+ code_props_usage: `
6292
+ const chartId = 'xy-multi-grouped-bar-${generateUniqueGeneralId()}'
6293
+ const chartRef = useRef(null)
6294
+ const [chartProps, setChartProps] = useState({
6295
+ chart: {
6296
+ paddingTop: 30
6297
+ },
6298
+ xAxis: {
6299
+ type: 'date',
6300
+ dateFormats: [
6301
+ { type: 'day', dateFormat: 'MM-dd' },
6302
+ { type: 'month', dateFormat: 'yy년 M월' }
6303
+ ],
6304
+ baseInterval: { timeUnit: 'month', count: 1 },
6305
+ gridHidden: true,
6306
+ cellStartLocation: 0.1,
6307
+ cellEndLocation: 0.9
6308
+ },
6309
+ yAxis: {
6310
+ type: 'value',
6311
+ numberFormat: '$#,###',
6312
+ extraMax: 0.08
6313
+ },
6314
+ series: {
6315
+ valueXField: 'date',
6316
+ dataProcessor: {
6317
+ dateFields: ['date'],
6318
+ dateFormat: 'yyyy-MM-dd'
6319
+ },
6320
+ bullet: {
6321
+ type: 'label',
6322
+ locationX: 0.5,
6323
+ locationY: 1,
6324
+ label: {
6325
+ dy: -2,
6326
+ text: '\${valueY.formatNumber("#,###")}', // amCharts5 포맷 문자열 직접 사용
6327
+ fontSize: 9
6328
+ }
6329
+ },
6330
+ seriesTypes: [
6331
+ {
6332
+ type: 'bar',
6333
+ categoryGroupName: 'cost_group',
6334
+ grouped: true
6335
+ }
6336
+ ],
6337
+ tooltip: {
6338
+ type: 'CG',
6339
+ header: { name: '{valueX.formatDate("yyyy년 M월")}' },
6340
+ body: {
6341
+ name: '{name}',
6342
+ value: '\${valueY.formatNumber("#,###")}',
6343
+ useMarker: true
6344
+ }
6345
+ }
6346
+ },
6347
+ legend: { useExtension: false }
6348
+ })
6349
+ const [chartData, setChartData] = useState([
6350
+ { date: '2024-10-01', costUsd: 79580, cloudCost: 81530 },
6351
+ { date: '2024-11-01', costUsd: 95812, cloudCost: 98903 },
6352
+ { date: '2024-12-01', costUsd: 182965, cloudCost: 188854 },
6353
+ { date: '2025-01-01', costUsd: 178695, cloudCost: 184359 },
6354
+ { date: '2025-02-01', costUsd: 103273, cloudCost: 106587 },
6355
+ { date: '2025-03-01', costUsd: 122976, cloudCost: 126556 },
6356
+ { date: '2025-04-01', costUsd: 151876, cloudCost: 155737 },
6357
+ { date: '2025-05-01', costUsd: 288608, cloudCost: 296687 },
6358
+ { date: '2025-06-01', costUsd: 146040, cloudCost: 149912 },
6359
+ { date: '2025-07-01', costUsd: 151794, cloudCost: 155419 },
6360
+ { date: '2025-08-01', costUsd: 147177, cloudCost: 150342 },
6361
+ { date: '2025-09-01', costUsd: 220261, cloudCost: 196047 }
6362
+ ])
6363
+ const [chartCategory, setChartCategory] = useState([
6364
+ { name: 'cost_group', categories: ['costUsd', 'cloudCost'] }
6365
+ ])
6366
+ const chartCategoryLocaleMapping = [
6367
+ { name: 'costUsd', value: 'Cost(USD, 청구)' },
6368
+ { name: 'cloudCost', value: '클라우드 사용요금' }
6369
+ ]
6370
+ const chartCustomCategory = [
6371
+ { name: 'costUsd', color: '#6B8E23' },
6372
+ { name: 'cloudCost', color: '#1976d2' }
6373
+ ]
6374
+ `,
6375
+ code: `<OpsnowCommonXyMultiChart
6376
+ chartId={chartId}
6377
+ chartRef={chartRef}
6378
+ chartProps={chartProps}
6379
+ chartCategory={chartCategory}
6380
+ chartData={chartData}
6381
+ chartCategoryLocaleMapping={chartCategoryLocaleMapping}
6382
+ chartCustomCategory={chartCustomCategory}
6383
+ />`
6384
+ },
5983
6385
  ];
@@ -1032,6 +1032,110 @@ export const DataGridExamples = [
1032
1032
  langCd={i18n.getLocale()}
1033
1033
  />`
1034
1034
  },
1035
+ {
1036
+ title: 'Data Bar',
1037
+ description: 'Excel 스타일의 Data Bar 예제입니다. 셀 배경에 값에 비례하는 막대를 표시합니다. 월별 비용 데이터를 시각화하는 예제입니다.',
1038
+ code_props_usage: `
1039
+ import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader'
1040
+ import i18n from '@opsnow-common/opsnow-finops-common-i18n'
1041
+
1042
+ // 월별 비용 데이터
1043
+ const initRowData = [
1044
+ { product: 'Amazon Elastic Compute Cloud', cost_202410: 11255, cost_202411: 18464, cost_202412: 17335, cost_202501: 18731, cost_202502: 20358, cost_202503: 27291 },
1045
+ { product: 'Amazon CloudFront', cost_202410: 10055, cost_202411: 13741, cost_202412: 12527, cost_202501: 14702, cost_202502: 17044, cost_202503: 23615 },
1046
+ { product: 'AWS Data Transfer', cost_202410: 13308, cost_202411: 18896, cost_202412: 16358, cost_202501: 16044, cost_202502: 15475, cost_202503: 21206 },
1047
+ { product: 'Amazon Relational Database Service', cost_202410: 12057, cost_202411: 13592, cost_202412: 12883, cost_202501: 11609, cost_202502: 10681, cost_202503: 13413 },
1048
+ { product: 'AmazonCloudWatch', cost_202410: 11107, cost_202411: 6883, cost_202412: 6623, cost_202501: 6391, cost_202502: 6295, cost_202503: 8128 },
1049
+ { product: 'Amazon Managed Streaming for Apache Kafka', cost_202410: 5555, cost_202411: 5423, cost_202412: 5555, cost_202501: 6131, cost_202502: 6193, cost_202503: 7631 },
1050
+ { product: 'Elastic Load Balancing', cost_202410: 2482, cost_202411: 4760, cost_202412: 3651, cost_202501: 4464, cost_202502: 4219, cost_202503: 6394 },
1051
+ { product: 'AWS WAF', cost_202410: 3714, cost_202411: 4362, cost_202412: 3768, cost_202501: 3490, cost_202502: 3776, cost_202503: 4905 },
1052
+ ]
1053
+
1054
+ // 월 필드 목록
1055
+ const monthFields = [
1056
+ 'cost_202410', 'cost_202411', 'cost_202412',
1057
+ 'cost_202501', 'cost_202502', 'cost_202503'
1058
+ ]
1059
+
1060
+ // 최대값 계산 (바 스케일링용)
1061
+ const maxCost = Math.max(...initRowData.flatMap(row =>
1062
+ monthFields.map(field => row[field])
1063
+ ))
1064
+
1065
+ // 합계 행 계산
1066
+ const totals = monthFields.reduce((acc, field) => {
1067
+ acc[field] = initRowData.reduce((sum, r) => sum + r[field], 0)
1068
+ return acc
1069
+ }, { product: 'Total' })
1070
+
1071
+ // 컬럼 정의
1072
+ const columnDefs = [
1073
+ { headerName: 'Product', field: 'product', colId: 'product', width: 280, pinned: 'left' },
1074
+ ...monthFields.map(field => {
1075
+ const year = field.slice(5, 9)
1076
+ const month = field.slice(9, 11)
1077
+ return {
1078
+ headerName: \`\${year}-\${month}\`,
1079
+ field: field,
1080
+ width: 120,
1081
+ type: ['dataBar'],
1082
+ cellRendererParams: {
1083
+ typeParams: {
1084
+ maxValue: maxCost, // 모든 컬럼에서 동일한 스케일 적용
1085
+ barColor: '#E91E8C', // 막대 색상
1086
+ barOpacity: 0.5, // 막대 투명도
1087
+ valuePrefix: '$', // 값 앞에 $ 표시
1088
+ },
1089
+ },
1090
+ }
1091
+ })
1092
+ ]
1093
+
1094
+ const gridOptions = {
1095
+ animateRows: true,
1096
+ tooltipShowDelay: 100,
1097
+ domLayout: 'autoHeight',
1098
+ pinnedBottomRowData: [totals], // 합계 행을 하단에 고정
1099
+ }
1100
+
1101
+ const defaultColDef = {
1102
+ suppressMenu: true,
1103
+ sortable: true,
1104
+ resizable: true,
1105
+ }
1106
+
1107
+ const { OpsnowCommonDataGrid } = useCommonComponents();
1108
+ const { CommonConst } = useGlobalContext()
1109
+ // rowData와 status 상태를 관리
1110
+ const [rowData, setRowData] = useState([]) // 초기에는 빈 배열로 설정
1111
+ const [status, setStatus] = useState(CommonConst.GRID_STATUS.LOADING) // 초기에는 LOADING 상태
1112
+ const gridRef = useRef(null)
1113
+
1114
+ // 데이터 지연 설정을 위한 useEffect
1115
+ useEffect(() => {
1116
+ // 1초 후에 데이터를 설정
1117
+ const timeoutId = setTimeout(() => {
1118
+ setRowData(initRowData)
1119
+ setStatus(CommonConst.GRID_STATUS.DATA_EXISTS)
1120
+ }, 1000)
1121
+
1122
+ // 컴포넌트 언마운트 시 타임아웃 클리어
1123
+ return () => {
1124
+ clearTimeout(timeoutId)
1125
+ }
1126
+ }, [])
1127
+ `,
1128
+ code: `<OpsnowCommonDataGrid
1129
+ ref={gridRef}
1130
+ key={status}
1131
+ columnDefs={columnDefs}
1132
+ defaultColDef={defaultColDef}
1133
+ rowData={rowData}
1134
+ status={status} // 상태를 전달
1135
+ gridOptions={gridOptions}
1136
+ langCd={i18n.getLocale()}
1137
+ />`
1138
+ },
1035
1139
  {
1036
1140
  title: 'How to insert into the slot to the left of the search',
1037
1141
  description: 'Search 왼쪽에 컴포넌트를 추가하는 방법입니다.',
@@ -2138,8 +2242,8 @@ export const DataGridExamples = [
2138
2242
  />`
2139
2243
  },
2140
2244
  {
2141
- title: 'Long Text with autoHeight',
2142
- description: 'Long Text with autoHeight (텍스트 자동 높이 조절) 예제입니다.',
2245
+ title: 'Auto Row Height',
2246
+ description: ' 높이 자동 조절 예제입니다. 다음 경우 반드시 적용: 1) 텍스트가 들어올 있는 컬럼이 있는 경우 (설명, 메시지, 항목, 이름, 제목, 등) 2) 컬럼이 resizable인 경우 - 폭을 줄여도 텍스트가 잘리지 않고 여러 줄로 정상 표시되어야 함 (ellipsis로 자르면 안됨)',
2143
2247
  code_props_usage: `
2144
2248
  import { useCommonComponents, useGlobalContext } from '@opsnow-common/opsnow-finops-common-ui-loader'
2145
2249
  import i18n from '@opsnow-common/opsnow-finops-common-i18n'
@@ -2157,9 +2261,11 @@ export const DataGridExamples = [
2157
2261
  field: 'description',
2158
2262
  flex: 3, // 가장 넓은 비율
2159
2263
  minWidth: 300,
2160
- suppressSizeToFit: true, // 자동 리사이즈 방지
2264
+ wrapText: true, // 텍스트 줄바꿈 - 필수
2265
+ autoHeight: true, // 행 높이 자동 조절 - 필수
2266
+ suppressSizeToFit: true, // 자동 리사이즈 방지
2161
2267
  cellStyle: {
2162
- 'align-items': 'center' // autoHeight 작동을 위해 필수
2268
+ alignItems: 'center' // autoHeight 작동을 위해 필수
2163
2269
  }
2164
2270
  },
2165
2271
  {
@@ -2194,11 +2300,16 @@ export const DataGridExamples = [
2194
2300
  },
2195
2301
  ]
2196
2302
 
2303
+ const defaultColDef = {
2304
+ wrapText: true, // 텍스트 줄바꿈 활성화
2305
+ autoHeight: true, // 셀 높이 자동 조절
2306
+ }
2307
+
2197
2308
  const gridOptions = {
2198
2309
  animateRows: true,
2199
2310
  rowSelection: { mode: 'singleRow', checkboxes: false, enableClickSelection: true },
2200
2311
  tooltipShowDelay: 100,
2201
- domLayout: 'autoHeight',
2312
+ domLayout: 'autoHeight', // 그리드 전체 레이아웃 자동 높이
2202
2313
  suppressCellFocus: true,
2203
2314
  }
2204
2315
 
@@ -2207,6 +2318,7 @@ export const DataGridExamples = [
2207
2318
  `,
2208
2319
  code: `<OpsnowCommonDataGrid
2209
2320
  columnDefs={columnDefs}
2321
+ defaultColDef={defaultColDef}
2210
2322
  rowData={rowData}
2211
2323
  status={CommonConst.GRID_STATUS.DATA_EXISTS}
2212
2324
  gridOptions={gridOptions}
@@ -76,10 +76,25 @@ const XyMultiChartSchema = z.object({
76
76
  "connect": true, // 라인 연결 여부
77
77
  "lineType": "smoothedX", // 라인 스무딩 타입
78
78
  "bullet": { // 불릿 설정, 라인 유형 차트에서 필수
79
- "type": "circle", // 불릿 타입: 'circle' | 'square' | 'triangle'
79
+ "type": "circle", // 불릿 타입: 'circle' | 'square' | 'triangle' | 'label'
80
80
  "lineOnly": true, // 라인만 표시 여부
81
81
  "cursorOverStyle": "pointer", // 마우스 오버시 커서 스타일
82
- "customField": "custom_bullet" // 불릿 커스텀 필드
82
+ "customField": "custom_bullet", // 불릿 커스텀 필드
83
+ "locationX": 0.5, // 불릿 X축 위치 (0~1, type이 'label'일 때 사용)
84
+ "locationY": 1, // 불릿 Y축 위치 (0~1, type이 'label'일 때 사용)
85
+ "label": { // 라벨 불릿 설정 (type이 'label'일 때 사용)
86
+ "dy": -10, // Y축 오프셋
87
+ "dx": 0, // X축 오프셋
88
+ "text": "{valueY}", // 라벨 텍스트
89
+ "fontSize": 12, // 폰트 크기
90
+ "format": "#,###", // 숫자 포맷
91
+ "prefix": "", // 접두사
92
+ "suffix": "", // 접미사
93
+ "background": { // 라벨 배경 설정
94
+ "fill": "#ffffff", // 배경 색상
95
+ "fillOpacity": 0.8 // 배경 투명도
96
+ }
97
+ }
83
98
  },
84
99
  "clickTarget": true, // 클릭 대상 여부
85
100
  "setPreviousToZero": false, // 이전 데이터를 0으로 설정 여부
@@ -401,6 +416,24 @@ export const StackChartSchema = z.object({
401
416
  },
402
417
  "sort": "byName" // 툴팁 정렬 방향: 'byName' | 'reverse'
403
418
  },
419
+ "bullet": { // 스택 차트의 블릿 설정 (선택 사항)
420
+ "type": "label", // 블릿 타입: 'circle' | 'square' | 'triangle' | 'label'
421
+ "locationX": 0.5, // 불릿 X축 위치 (0~1, type이 'label'일 때 사용)
422
+ "locationY": 1, // 불릿 Y축 위치 (0~1, type이 'label'일 때 사용)
423
+ "label": { // 라벨 불릿 설정 (type이 'label'일 때 사용)
424
+ "dy": -10, // Y축 오프셋
425
+ "dx": 0, // X축 오프셋
426
+ "text": "{valueY}", // 라벨 텍스트
427
+ "fontSize": 12, // 폰트 크기
428
+ "format": "#,###", // 숫자 포맷
429
+ "prefix": "", // 접두사
430
+ "suffix": "", // 접미사
431
+ "background": { // 라벨 배경 설정
432
+ "fill": "#ffffff", // 배경 색상
433
+ "fillOpacity": 0.8 // 배경 투명도
434
+ }
435
+ }
436
+ },
404
437
  "topNOthers": { // Top N + Others 옵션
405
438
  "topN": 5, // 상위 N개 항목만 표시
406
439
  "othersName": "Others", // 기타 항목의 이름 (기본값: 'Others')
@@ -414,7 +447,7 @@ export const StackChartSchema = z.object({
414
447
  "delay": 500 // 애니메이션 지연 시간
415
448
  }
416
449
  },
417
-
450
+
418
451
  // 범례 설정
419
452
  "legend": {
420
453
  "clickTarget": "none", // 범례 클릭 대상: "none" | "" (기본값: "none")
@@ -441,7 +474,7 @@ export const StackChartSchema = z.object({
441
474
  [
442
475
  {
443
476
  'date': '2022-07-01',
444
- 'cost_test_01': 3,
477
+ 'cost_test_01': 3,
445
478
  'cost_test_02': 7
446
479
  },
447
480
  {
@@ -455,7 +488,7 @@ export const StackChartSchema = z.object({
455
488
  [
456
489
  {
457
490
  'date': '2022-07-01',
458
- 'cost_test_01': 3,
491
+ 'cost_test_01': 3,
459
492
  'cost_test_02': 7
460
493
  },
461
494
  {
@@ -534,7 +567,7 @@ export const StackChartSchema = z.object({
534
567
  }))
535
568
  .optional()
536
569
  .describe("사용자 정의 카테고리 스타일 및 설정"),
537
- // 기타 설정
570
+ // 기타 설정
538
571
  chartTooltipDetailText: z.string()
539
572
  .optional()
540
573
  .describe("툴팁에서 보여주는 상세 텍스트"),
@@ -644,6 +677,24 @@ export const BarChartSchema = z.object({
644
677
  },
645
678
  "sort": "byName" // 툴팁 정렬 방향: 'byName' | 'reverse'
646
679
  },
680
+ "bullet": { // 바 차트의 블릿 설정 (선택 사항)
681
+ "type": "label", // 블릿 타입: 'circle' | 'square' | 'triangle' | 'label'
682
+ "locationX": 0.5, // 불릿 X축 위치 (0~1, type이 'label'일 때 사용)
683
+ "locationY": 1, // 불릿 Y축 위치 (0~1, type이 'label'일 때 사용)
684
+ "label": { // 라벨 불릿 설정 (type이 'label'일 때 사용)
685
+ "dy": -10, // Y축 오프셋
686
+ "dx": 0, // X축 오프셋
687
+ "text": "{valueY}", // 라벨 텍스트
688
+ "fontSize": 12, // 폰트 크기
689
+ "format": "#,###", // 숫자 포맷
690
+ "prefix": "", // 접두사
691
+ "suffix": "", // 접미사
692
+ "background": { // 라벨 배경 설정
693
+ "fill": "#ffffff", // 배경 색상
694
+ "fillOpacity": 0.8 // 배경 투명도
695
+ }
696
+ }
697
+ },
647
698
  "topNOthers": { // Top N + Others 옵션
648
699
  "topN": 5, // 상위 N개 항목만 표시
649
700
  "othersName": "Others", // 기타 항목의 이름 (기본값: 'Others')
@@ -657,7 +708,7 @@ export const BarChartSchema = z.object({
657
708
  "delay": 500 // 애니메이션 지연 시간
658
709
  }
659
710
  },
660
-
711
+
661
712
  // 범례 설정
662
713
  "legend": {
663
714
  "clickTarget": "none", // 범례 클릭 대상: "none" | "" (기본값: "none")
@@ -682,7 +733,7 @@ export const BarChartSchema = z.object({
682
733
  [
683
734
  {
684
735
  'date': '2022-07-01',
685
- 'cost_test_01': 3,
736
+ 'cost_test_01': 3,
686
737
  'cost_test_02': 7
687
738
  },
688
739
  {
@@ -696,7 +747,7 @@ export const BarChartSchema = z.object({
696
747
  [
697
748
  {
698
749
  'date': '2022-07-01',
699
- 'cost_test_01': 3,
750
+ 'cost_test_01': 3,
700
751
  'cost_test_02': 7
701
752
  },
702
753
  {
@@ -870,9 +921,24 @@ export const LineChartSchema = z.object({
870
921
  "dateFormat": "yyyy-MM-dd" // dateFields에 지정된 필드의 날짜 형식
871
922
  },
872
923
  "bullet": { // 라인 차트의 블릿 설정으로 필수 속성
873
- "type": "circle", // 라인 차트의 블릿 타입 (기본값: "circle")
924
+ "type": "circle", // 라인 차트의 블릿 타입: 'circle' | 'square' | 'triangle' | 'label' (기본값: "circle")
874
925
  "cursorOverStyle": "pointer", // 커서 오버 스타일, 클릭 대상이 true일 때 사용: "pointer" | "hand" (기본값: "pointer")
875
- "lineOnly": false // 라인만 표시 여부 (기본값: false)
926
+ "lineOnly": false, // 라인만 표시 여부 (기본값: false)
927
+ "locationX": 0.5, // 불릿 X축 위치 (0~1, type이 'label'일 때 사용)
928
+ "locationY": 1, // 불릿 Y축 위치 (0~1, type이 'label'일 때 사용)
929
+ "label": { // 라벨 불릿 설정 (type이 'label'일 때 사용)
930
+ "dy": -10, // Y축 오프셋
931
+ "dx": 0, // X축 오프셋
932
+ "text": "{valueY}", // 라벨 텍스트
933
+ "fontSize": 12, // 폰트 크기
934
+ "format": "#,###", // 숫자 포맷
935
+ "prefix": "", // 접두사
936
+ "suffix": "", // 접미사
937
+ "background": { // 라벨 배경 설정
938
+ "fill": "#ffffff", // 배경 색상
939
+ "fillOpacity": 0.8 // 배경 투명도
940
+ }
941
+ }
876
942
  },
877
943
  "tooltip": { // 툴팁 설정(툴팁 설정시 body 설정 필수)
878
944
  "type": "CG", // CI: 각 카테고리를 보여줄때 | CG: 모든 카테고리를 보여줄때
@@ -1343,7 +1409,10 @@ export function createChartComponent() {
1343
1409
  description: `바 차트 컴포넌트 - 바 차트 시각화 지원
1344
1410
 
1345
1411
  **이 차트 컴포넌트는 amCharts5를 기반으로 구현되었습니다.**
1346
-
1412
+
1413
+ **주의: Grouped Bar Chart(묶음 막대 차트)는 이 컴포넌트가 아닌 OpsnowCommonXyMultiChart를 사용해야 합니다.**
1414
+ Grouped Bar Chart란 각 카테고리에서 여러 시리즈의 막대가 나란히 배치되는 차트입니다.
1415
+
1347
1416
  **import:**
1348
1417
  \`\`\`javascript
1349
1418
  import { useCommonComponents } from '@opsnow-common/opsnow-finops-common-ui-loader';
@@ -1457,7 +1526,10 @@ export function createChartComponent() {
1457
1526
  description: `XY 멀티 차트 컴포넌트 - XY 멀티 차트 시각화 지원
1458
1527
 
1459
1528
  **이 차트 컴포넌트는 amCharts5를 기반으로 구현되었습니다.**
1460
-
1529
+
1530
+ **Grouped Bar Chart(묶음 막대 차트)를 만들려면 이 컴포넌트를 사용하세요.**
1531
+ series의 type을 'grouped'로 설정하면 각 카테고리에서 여러 시리즈의 막대가 나란히 배치됩니다.
1532
+
1461
1533
  **import:**
1462
1534
  \`\`\`javascript
1463
1535
  import { useCommonComponents } from '@opsnow-common/opsnow-finops-common-ui-loader';
@@ -47,8 +47,11 @@ const columnDefsSchema = z.lazy(() => z.object({
47
47
  'mixFormat',
48
48
  'numberTooltip',
49
49
  'ratioBar',
50
+ 'dataBar',
50
51
  'value'
51
- ])).optional().describe('컬럼 타입'),
52
+ ])).optional().describe(`컬럼 타입.
53
+ - ratioBar: 여러 색상/세그먼트로 구성 비율을 보여주는 스택 차트 스타일 바. 여러 필드의 비율을 시각화할 때 사용 (예: Cost Composition by Type). 'Ratio Bar' 예제 참고.
54
+ - dataBar: 단일 색상으로 셀 배경을 값에 비례하여 채우는 Excel 스타일 바. 단일 값의 크기를 시각화할 때 사용 (예: 월별 비용 트렌드). 'Data Bar' 예제 참고.`),
52
55
  cellRenderer: z.any().optional().describe('셀 렌더러'),
53
56
  cellRendererParams: z.object({
54
57
  typeParams: z.object({
@@ -205,26 +208,36 @@ export function createDataGridComponent() {
205
208
  **이 데이터 그리드 컴포넌트는 ag-grid를 기반으로 구현되었습니다.**
206
209
  **데이터 그리드 데이터, 컬럼 정의 등의 데이터가 제공되지 않을 경우 목업 데이터를 사용하세요.**
207
210
 
208
- **중요: 텍스트 컬럼 처리 (필수)**
209
- 컬럼 값이 길어서 줄바꿈이 필요한 경우, 반드시 다음을 따라야 합니다:
210
- 1. 모든 컬럼에 flex 속성 필수 (비율로 너비 분배, 예: flex: 1, flex: 3)
211
- 2. 긴 텍스트 컬럼에 suppressSizeToFit: true 필수
212
- 3. 긴 텍스트 컬럼에 cellStyle: { 'align-items': 'center' } 필수
213
- 4. gridOptions에 domLayout: 'autoHeight' 설정
211
+ **CRITICAL: Auto Row Height - 다음 경우 반드시 적용**
212
+ 1. 텍스트가 들어올 있는 컬럼이 있는 경우 (설명, 메시지, 항목, 이름, 제목, 코멘트, 비고, 등)
213
+ 2. 컬럼이 resizable인 경우 - 사용자가 폭을 줄여도 텍스트가 잘리지 않고 여러 줄로 정상 표시되어야 함 (ellipsis로 자르면 안됨)
214
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
- ];
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가 없으면 텍스트가 넘칩니다!
228
241
 
229
242
  **import:**
230
243
  \`\`\`javascript
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opsnow-mcp/opsnow-mcp-common-ui-server",
3
- "version": "1.0.10",
3
+ "version": "1.0.12",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "bin": {