@opsnow-mcp/opsnow-mcp-common-ui-server 1.0.37 → 1.0.39

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.
@@ -1755,6 +1755,34 @@ const multiCspRateInfo = {
1755
1755
  />`,
1756
1756
  description: "수집 통화 분리 — 멀티 CSP 혼재 예제입니다. 기준 통화(USD)는 환율 앵커로 유지하되 '변환 없음(Default)' 문구는 nativeCurrency='KRW' 행에 붙습니다. USD 행에는 'N개 환율' 배지가 붙고, 히스토리 테이블 행 라벨에는 실제 환산 통화가 'Azure · Invoice 1111 (KRW)'처럼 병기됩니다 — USD로 보는 것 자체가 KRW 환율로 나누는 환산이기 때문입니다. 시리즈에도 currency 필드를 담아 주입하세요. [검색 키워드: 멀티 CSP, 수집 통화, 무환산, nativeCurrency, 행 단위 통화]"
1757
1757
  },
1758
+ {
1759
+ title: 'rate-simulation',
1760
+ code: `// ⚠️ 단독 배치는 props 참고용 — 실서비스 배치는 header-currency-switcher 예제처럼 currencySwitcherProps에 동일하게 주입
1761
+ // 환율 설정(직접 입력 · 시뮬레이션) — 2.0.11+ 동작
1762
+ // 노출 판정: showDetail && simulationAnchorCurrency 지정 && simulationAnchorCurrency !== 선택 통화
1763
+ // → USD 선택 중에도 앵커(KRW)와 다르면 노출된다 ('USD면 미노출' 내부 규칙 없음)
1764
+ const [currency, setCurrency] = useState('USD')
1765
+ const [customRate, setCustomRate] = useState(null) // 앵커 통화 1단위당 값 (null = 빈 입력)
1766
+
1767
+ <OpsnowCommonCurrencySwitcher
1768
+ value={currency}
1769
+ onChange={handleCurrencyChange}
1770
+ rateInfo={rateInfo}
1771
+ historySeries={historySeries}
1772
+ onHistoryQueryChange={handleHistoryQueryChange}
1773
+
1774
+ showDetail // 기본 false — 미사용 소비자는 변화 없음
1775
+ simulationAnchorCurrency="KRW" // 입력 라벨: 1 KRW = [입력] {선택 통화}
1776
+ customRate={customRate} // controlled — 팝오버 열 때 입력이 이 값으로 동기화
1777
+ onCustomRateChange={(rate, context) => {
1778
+ // 적용(또는 Enter) 시 입력값, 초기화·통화 변경 시 null — 입력 중에는 호출되지 않음
1779
+ // context.currency 는 3곳 모두 항상 simulationAnchorCurrency ('KRW')
1780
+ setCustomRate(rate)
1781
+ applyWhatIfRate(rate, context.currency) // 저장되지 않는 what-if 값 — 화면 환산에만 반영
1782
+ }}
1783
+ />`,
1784
+ description: "환율 직접 입력(시뮬레이션) 예제입니다 (2.0.11+). 시뮬레이션 섹션은 showDetail && simulationAnchorCurrency 지정 && 앵커 !== 선택 통화 3조건으로만 노출되며, 선택 통화가 USD여도 앵커가 다르면 노출됩니다. 입력 라벨은 '1 {simulationAnchorCurrency} = [입력] {선택 통화}'이고 입력창에 현재 환율 placeholder는 없습니다. onCustomRateChange의 context.currency는 적용·초기화·통화 변경 모두 항상 simulationAnchorCurrency이며, 값은 적용/Enter 시 입력값·초기화/통화 변경 시 null로 통지됩니다(입력 중 미호출). defaultTargetCurrency·simulationTarget은 @deprecated로 무시되니 앵커는 simulationAnchorCurrency로 지정하세요. [검색 키워드: 환율 시뮬레이션, 직접 입력, what-if, 커스텀 환율, showDetail, simulationAnchorCurrency, customRate]"
1785
+ },
1758
1786
  ];
1759
1787
  export const ToggleButtonExamples = [
1760
1788
  {
@@ -308,14 +308,11 @@ export const CurrencySwitcherSchema = z.object({
308
308
  labels: z.string().optional().describe("문구 개별 커스텀 객체 변수명 — Partial<CurrencySwitcherLabels>, 우선순위 labels > 앱 i18n 리소스(common.currency_switcher.*) > 패키지 내장 ko/en/ja ({placeholder} 템플릿 치환 지원). 기준 통화 행 문구는 baseCurrencyDescription, 히스토리 테이블 첫 컬럼 머리는 payerColumnLabel 키로 교체"),
309
309
  size: z.enum(["small", "medium"]).optional().describe("트리거 크기"),
310
310
  disabled: z.boolean().optional().describe("비활성화 여부"),
311
- // [다음 버전 재도입 예정] 환율 설정(직접 입력 · 시뮬레이션) 영역 props — dropdown 컴포넌트 쪽
312
- // '[다음 버전 재도입 예정]' 주석 블록이 되살아나면 아래 주석 해제 (핸들러 쪽 주석 블록도 함께)
313
- // defaultTargetCurrency: z.string().optional().describe("기준 통화 선택 중일 때 환율 설정이 다룰 초기 비교 통화 코드"),
314
- // simulationTarget: z.string().optional().describe("환율 설정(시뮬레이션) 대상 지정 객체 변수명 — { currency, payer?, invoice? } 형태, 기준 통화 뷰에서 실제 환산되는 CSP(Payer)로 고정하며 payer/invoice 일치 행이 사전 선택됨 (예: simulationTarget)"),
315
- // customRate: z.string().optional().describe("직접 입력 시뮬레이션 환율 상태 변수명 (number | null, controlled 모드 — 미지정 시 내부 관리)"),
316
- // onCustomRateChange: z.string().optional().describe("직접 입력 환율 변경 핸들러 함수명 — (rate, context) => void 형태, 저장되지 않는 what-if 값 통지 (onChange는 호출되지 않음)"),
317
- // showDetail: z.boolean().optional().describe("환율 설정(직접 입력 시뮬레이션) 섹션 노출 여부 (기본값: true)"),
318
- // historyMode: z.enum(["auto", "popup"]).optional().describe("히스토리 열림 방식 — 'popup'이면 항상 화면 중앙 팝업, 'auto'는 다중 환율=팝업/단일 환율·기준 통화=인라인 분기 (기본값: 'auto')"),
311
+ // 환율 설정(직접 입력 · 시뮬레이션) 영역 props — dropdown 컴포넌트 쪽. 대상(앵커) 통화는 항상 simulationAnchorCurrency
312
+ simulationAnchorCurrency: z.string().optional().describe("시뮬레이션 앵커 통화 코드 — 입력 좌변('1 {anchor} =')의 통화이자 onCustomRateChange context.currency로 통지되는 값. 미지정이면 시뮬레이션 섹션이 노출되지 않음 (showDetail과 무관). 선택 통화와 같을 때도 노출되지 않음 (예: 'KRW')"),
313
+ customRate: z.string().optional().describe("직접 입력 시뮬레이션 환율 상태 변수명 (number | null, controlled) — 앵커 통화 1단위당 값. number면 입력에 표시, null이면 빈 입력(placeholder 없음). 팝오버를 열 때 이 값으로 입력이 동기화됨"),
314
+ onCustomRateChange: z.string().optional().describe("직접 입력 환율 확정 핸들러 함수명 — (rate, context) => void 형태. 적용(또는 Enter) 시 입력값, 초기화·통화 변경 시 null로 호출되고 입력 중에는 호출되지 않음. context.currency는 항상 simulationAnchorCurrency. 저장되지 않는 what-if 값 통지 (onChange는 호출되지 않음)"),
315
+ showDetail: z.boolean().optional().describe("환율 설정(직접 입력 시뮬레이션) 섹션 노출 여부 (기본값: false). 실제 노출은 showDetail && simulationAnchorCurrency 지정 && simulationAnchorCurrency !== 선택 통화 3조건으로 판정 — 선택 통화가 기준 통화(USD)여도 앵커와 다르면 노출됨"),
319
316
  });
320
317
  // Forms 컴포넌트 함수 - 배열 반환
321
318
  export function createFormsComponent() {
@@ -1153,6 +1150,14 @@ export function createFormsComponent() {
1153
1150
  - 통화 선택 시 onChange(currency, rate)가 호출됩니다 — 금액 표시 변환은 소비 프로젝트에서 rate로 처리
1154
1151
  - 문구는 i18n 현재 언어(ko/en/ja)를 자동으로 따르고, labels prop으로 항목별 커스텀 가능 (우선순위: labels > 앱 i18n 리소스 common.currency_switcher.* > 패키지 내장 문구. 기준 통화 행 문구는 baseCurrencyDescription, 히스토리 테이블 첫 컬럼 머리는 payerColumnLabel 키)
1155
1152
 
1153
+ **환율 설정(직접 입력 · 시뮬레이션) 규칙 (2.0.11+):**
1154
+ - 노출 판정은 showDetail && simulationAnchorCurrency 지정 && simulationAnchorCurrency !== 선택 통화 3조건뿐입니다 — '선택 통화가 USD면 미노출' 같은 내부 고정 규칙은 없어 USD 선택 중에도 앵커가 다르면 노출됩니다
1155
+ - 입력 라벨은 '1 {simulationAnchorCurrency} = [입력] {선택 통화}' — 좌변이 앵커 통화, 우변이 현재 선택 통화입니다. 입력창에 현재 환율 placeholder(회색 숫자)는 표시되지 않습니다
1156
+ - onCustomRateChange(rate, context)의 context.currency는 적용·초기화·통화 변경 3곳 모두 항상 simulationAnchorCurrency입니다. 적용(또는 Enter) 시 입력값, 초기화·통화 변경 시 null로 호출되고 입력 중에는 호출되지 않습니다
1157
+ - customRate는 앵커 통화 1단위당 값(number | null, controlled)이며 팝오버를 열 때 입력이 이 값으로 동기화됩니다
1158
+ - defaultTargetCurrency · simulationTarget · historyMode는 @deprecated로 무시됩니다 — 앵커 통화는 simulationAnchorCurrency로 지정하세요
1159
+ - showDetail 기본값은 false — 시뮬레이션 props를 쓰지 않는 소비자는 아무 변화가 없습니다
1160
+
1156
1161
  **공통 헤더에서 쓰기 (OpsnowFinopsCommonHeader):**
1157
1162
  - 실서비스 배치는 **무조건 공통 헤더를 통해서** 합니다 — 페이지 본문에 단독 배치하지 마세요 (단독 예제는 props 사용법 참고용)
1158
1163
  - 헤더는 AI 버튼~알림 벨 사이 자리만 제공하고 상태·환율 데이터를 갖지 않습니다 — 앱이 관리하는 값을 currencySwitcherProps로 주입하면 내부 OpsnowCommonCurrencySwitcher에 그대로 전달됩니다 (위 props 규칙 동일 적용) - **활성/비활성 정책**: 통화 변경은 '개요(OverView)' · '비용 분석(Analytics)' · '청구 내역(Billing Invoice)' · '비용 배분(Cost Allocation)' 4개 메뉴에서만 허용됩니다 — 그 외 메뉴 진입 시 currencySwitcherEnabled={false}로 넘겨 버튼을 disabled 상태로 노출하고, 호버 시 안내 툴팁이 표시됩니다 (문구는 내장 ko/en/ja 기본, currencySwitcherDisabledTooltip으로 덮어쓰기 가능). 적용 라우트: '/overview' · '/cost/analytics/usage-charges' · '/cost/billing-invoice' · '/settings/cost-allocation'(하위 경로 포함) — 현재 라우트가 여기에 속하는지를 앱에서 판단해 주입하세요
@@ -1201,13 +1206,14 @@ export function createFormsComponent() {
1201
1206
  entries.push(["baseCurrency", `'${args.baseCurrency}'`]);
1202
1207
  if (args.nativeCurrency)
1203
1208
  entries.push(["nativeCurrency", `'${args.nativeCurrency}'`]);
1204
- // [다음 버전 재도입 예정] 환율 설정(직접 입력 · 시뮬레이션) props — 스키마 주석 블록과 함께 주석 해제
1205
- // if (args.defaultTargetCurrency) entries.push(["defaultTargetCurrency", `'${args.defaultTargetCurrency}'`]);
1206
- // if (args.simulationTarget) entries.push(["simulationTarget", args.simulationTarget]);
1207
- // if (args.customRate) entries.push(["customRate", args.customRate]);
1208
- // if (args.onCustomRateChange) entries.push(["onCustomRateChange", args.onCustomRateChange]);
1209
- // if (args.showDetail !== undefined) entries.push(["showDetail", String(args.showDetail)]);
1210
- // if (args.historyMode) entries.push(["historyMode", `'${args.historyMode}'`]);
1209
+ if (args.simulationAnchorCurrency)
1210
+ entries.push(["simulationAnchorCurrency", `'${args.simulationAnchorCurrency}'`]);
1211
+ if (args.customRate)
1212
+ entries.push(["customRate", args.customRate]);
1213
+ if (args.onCustomRateChange)
1214
+ entries.push(["onCustomRateChange", args.onCustomRateChange]);
1215
+ if (args.showDetail !== undefined)
1216
+ entries.push(["showDetail", String(args.showDetail)]);
1211
1217
  if (args.showHistory !== undefined)
1212
1218
  entries.push(["showHistory", String(args.showHistory)]);
1213
1219
  if (args.renderChart)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opsnow-mcp/opsnow-mcp-common-ui-server",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "bin": {