@opsnow-mcp/opsnow-mcp-common-ui-server 1.0.38 → 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,10 +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 컴포넌트 쪽. 대상 통화는 항상 현재 선택 통화(value)
312
- customRate: z.string().optional().describe("직접 입력 시뮬레이션 환율 상태 변수명 (number | null, controlled 모드 — 미지정 시 내부 관리)"),
313
- onCustomRateChange: z.string().optional().describe("직접 입력 환율 변경 핸들러 함수명 — (rate, context) => void 형태, 저장되지 않는 what-if 값 통지 (onChange는 호출되지 않음)"),
314
- showDetail: z.boolean().optional().describe("환율 설정(직접 입력 시뮬레이션) 섹션 노출 여부 (기본값: false). true여도 선택 통화가 기준 통화면 환산이 없어 노출되지 않음"),
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)여도 앵커와 다르면 노출됨"),
315
316
  });
316
317
  // Forms 컴포넌트 함수 - 배열 반환
317
318
  export function createFormsComponent() {
@@ -1149,6 +1150,14 @@ export function createFormsComponent() {
1149
1150
  - 통화 선택 시 onChange(currency, rate)가 호출됩니다 — 금액 표시 변환은 소비 프로젝트에서 rate로 처리
1150
1151
  - 문구는 i18n 현재 언어(ko/en/ja)를 자동으로 따르고, labels prop으로 항목별 커스텀 가능 (우선순위: labels > 앱 i18n 리소스 common.currency_switcher.* > 패키지 내장 문구. 기준 통화 행 문구는 baseCurrencyDescription, 히스토리 테이블 첫 컬럼 머리는 payerColumnLabel 키)
1151
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
+
1152
1161
  **공통 헤더에서 쓰기 (OpsnowFinopsCommonHeader):**
1153
1162
  - 실서비스 배치는 **무조건 공통 헤더를 통해서** 합니다 — 페이지 본문에 단독 배치하지 마세요 (단독 예제는 props 사용법 참고용)
1154
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'(하위 경로 포함) — 현재 라우트가 여기에 속하는지를 앱에서 판단해 주입하세요
@@ -1197,6 +1206,8 @@ export function createFormsComponent() {
1197
1206
  entries.push(["baseCurrency", `'${args.baseCurrency}'`]);
1198
1207
  if (args.nativeCurrency)
1199
1208
  entries.push(["nativeCurrency", `'${args.nativeCurrency}'`]);
1209
+ if (args.simulationAnchorCurrency)
1210
+ entries.push(["simulationAnchorCurrency", `'${args.simulationAnchorCurrency}'`]);
1200
1211
  if (args.customRate)
1201
1212
  entries.push(["customRate", args.customRate]);
1202
1213
  if (args.onCustomRateChange)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opsnow-mcp/opsnow-mcp-common-ui-server",
3
- "version": "1.0.38",
3
+ "version": "1.0.39",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "bin": {