Conversation
closes #3859 implements copy and paste from arbitrary distributions support ctrl+c and ctrl+v
📝 WalkthroughWalkthroughThis PR adds multilingual localization strings for distribution clipboard operations (copy/paste success/failure messages and action labels) across six language files, and implements a new Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant CM as ContinuousClipboardMenu
participant CB as Browser Clipboard
participant Parent as Parent State Manager
Note over CM: Copy Flow
User->>CM: Click copy button (or Ctrl+C)
CM->>CM: Serialize {marker, type, sliders/quantiles}
CM->>CB: navigator.clipboard.writeText(JSON)
CB-->>CM: Success/Error
alt Copy Success
CM->>User: Toast: distributionCopied
else Copy Failed
CM->>User: Toast: distributionCopyFailed
end
Note over CM: Paste Flow
User->>CM: Click paste button (or Ctrl+V)
CM->>CB: navigator.clipboard.readText()
CB-->>CM: Clipboard text
CM->>CM: Parse JSON & validate<br/>(marker check, type check)
alt Validation Success
CM->>Parent: onPaste(type, components)
Parent->>Parent: Update state<br/>Mark quantiles dirty<br/>Switch input mode
CM->>User: Toast: distributionPasted
else Validation Failed
CM->>User: Toast: distributionPasteInvalid
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@front_end/messages/zh-TW.json`:
- Around line 2081-2086: Update the translation values for the keys
"distributionCopied", "distributionCopyFailed", "distributionPasted",
"distributionPasteInvalid", "copyDistribution", and "pasteDistribution" to use
「分佈」 instead of 「分配」 so the terminology matches the forecasting context; locate
these string values in front_end/messages/zh-TW.json (the keys listed above) and
replace each occurrence of 「分配」 with 「分佈」 while preserving the rest of the
messages.
In
`@front_end/src/components/forecast_maker/continuous_input/continuous_clipboard_menu.tsx`:
- Around line 24-36: The isClipboardDistribution type guard currently checks
marker and type but must also validate that (data as
ClipboardDistribution).components is an array and that each component has the
required shape: ensure components is Array.isArray(...) and for each element
verify a discriminant (e.g., component.type or similar) and then for slider
components confirm presence and correct types for weight, left, center, right,
and for quantile components confirm presence and correct type for quantile; keep
referencing CLIPBOARD_MARKER, VALID_INPUT_TYPES and the ClipboardDistribution
shape and update isClipboardDistribution to return false for any malformed
component to prevent downstream runtime errors.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2628ab1d-d8ec-4edf-b54a-c454fc13fba0
📒 Files selected for processing (11)
front_end/messages/cs.jsonfront_end/messages/en.jsonfront_end/messages/es.jsonfront_end/messages/pt.jsonfront_end/messages/zh-TW.jsonfront_end/messages/zh.jsonfront_end/src/components/forecast_maker/continuous_input/continuous_clipboard_menu.tsxfront_end/src/components/forecast_maker/continuous_input/continuous_input_container.tsxfront_end/src/components/forecast_maker/continuous_input/index.tsxfront_end/src/components/forecast_maker/forecast_maker_group/continuous_input_wrapper.tsxfront_end/src/components/forecast_maker/forecast_maker_question/forecast_maker_continuous.tsx
| "distributionCopied": "分配已複製到剪貼簿", | ||
| "distributionCopyFailed": "複製分配失敗", | ||
| "distributionPasted": "從剪貼簿貼上了分配", | ||
| "distributionPasteInvalid": "剪貼簿中未找到有效的分配", | ||
| "copyDistribution": "將分配複製到剪貼簿", | ||
| "pasteDistribution": "從剪貼簿貼上分配", |
There was a problem hiding this comment.
Use 「分佈」 instead of 「分配」 for consistency and correctness.
In this locale file, distribution in forecasting context is already translated as 「分佈」. Using 「分配」 here introduces inconsistent terminology and reads as “allocation.”
Suggested wording update
- "distributionCopied": "分配已複製到剪貼簿",
- "distributionCopyFailed": "複製分配失敗",
- "distributionPasted": "從剪貼簿貼上了分配",
- "distributionPasteInvalid": "剪貼簿中未找到有效的分配",
- "copyDistribution": "將分配複製到剪貼簿",
- "pasteDistribution": "從剪貼簿貼上分配",
+ "distributionCopied": "分佈已複製到剪貼簿",
+ "distributionCopyFailed": "複製分佈失敗",
+ "distributionPasted": "已從剪貼簿貼上分佈",
+ "distributionPasteInvalid": "剪貼簿中未找到有效的分佈",
+ "copyDistribution": "將分佈複製到剪貼簿",
+ "pasteDistribution": "從剪貼簿貼上分佈",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "distributionCopied": "分配已複製到剪貼簿", | |
| "distributionCopyFailed": "複製分配失敗", | |
| "distributionPasted": "從剪貼簿貼上了分配", | |
| "distributionPasteInvalid": "剪貼簿中未找到有效的分配", | |
| "copyDistribution": "將分配複製到剪貼簿", | |
| "pasteDistribution": "從剪貼簿貼上分配", | |
| "distributionCopied": "分佈已複製到剪貼簿", | |
| "distributionCopyFailed": "複製分佈失敗", | |
| "distributionPasted": "已從剪貼簿貼上分佈", | |
| "distributionPasteInvalid": "剪貼簿中未找到有效的分佈", | |
| "copyDistribution": "將分佈複製到剪貼簿", | |
| "pasteDistribution": "從剪貼簿貼上分佈", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@front_end/messages/zh-TW.json` around lines 2081 - 2086, Update the
translation values for the keys "distributionCopied", "distributionCopyFailed",
"distributionPasted", "distributionPasteInvalid", "copyDistribution", and
"pasteDistribution" to use 「分佈」 instead of 「分配」 so the terminology matches the
forecasting context; locate these string values in front_end/messages/zh-TW.json
(the keys listed above) and replace each occurrence of 「分配」 with 「分佈」 while
preserving the rest of the messages.
| function isClipboardDistribution( | ||
| data: unknown | ||
| ): data is ClipboardDistribution { | ||
| return ( | ||
| typeof data === "object" && | ||
| data !== null && | ||
| CLIPBOARD_MARKER in data && | ||
| (data as ClipboardDistribution)[CLIPBOARD_MARKER] === true && | ||
| "type" in data && | ||
| "components" in data && | ||
| VALID_INPUT_TYPES.includes((data as ClipboardDistribution).type) | ||
| ); | ||
| } |
There was a problem hiding this comment.
Strengthen validation to include component structure checks.
The isClipboardDistribution type guard validates the marker and type but does not verify the structure of components. Malformed clipboard data could cause runtime errors downstream when:
componentsis not an array (.map()will fail)- Slider components are missing required fields (
weight,left,center,right) - Quantile components are missing the
quantilefield
🛡️ Proposed fix to add component structure validation
+function isValidSliderComponent(c: unknown): c is DistributionSliderComponent {
+ return (
+ typeof c === "object" &&
+ c !== null &&
+ typeof (c as DistributionSliderComponent).weight === "number" &&
+ typeof (c as DistributionSliderComponent).left === "number" &&
+ typeof (c as DistributionSliderComponent).center === "number" &&
+ typeof (c as DistributionSliderComponent).right === "number"
+ );
+}
+
+function isValidQuantileComponent(c: unknown): c is DistributionQuantileComponent[number] {
+ return (
+ typeof c === "object" &&
+ c !== null &&
+ "quantile" in c
+ );
+}
+
function isClipboardDistribution(
data: unknown
): data is ClipboardDistribution {
- return (
+ if (!(
typeof data === "object" &&
data !== null &&
CLIPBOARD_MARKER in data &&
(data as ClipboardDistribution)[CLIPBOARD_MARKER] === true &&
"type" in data &&
"components" in data &&
VALID_INPUT_TYPES.includes((data as ClipboardDistribution).type)
- );
+ )) {
+ return false;
+ }
+
+ const { type, components } = data as ClipboardDistribution;
+ if (!Array.isArray(components) || components.length === 0) {
+ return false;
+ }
+
+ if (type === ContinuousForecastInputType.Slider) {
+ return components.every(isValidSliderComponent);
+ }
+ return components.every(isValidQuantileComponent);
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function isClipboardDistribution( | |
| data: unknown | |
| ): data is ClipboardDistribution { | |
| return ( | |
| typeof data === "object" && | |
| data !== null && | |
| CLIPBOARD_MARKER in data && | |
| (data as ClipboardDistribution)[CLIPBOARD_MARKER] === true && | |
| "type" in data && | |
| "components" in data && | |
| VALID_INPUT_TYPES.includes((data as ClipboardDistribution).type) | |
| ); | |
| } | |
| function isValidSliderComponent(c: unknown): c is DistributionSliderComponent { | |
| return ( | |
| typeof c === "object" && | |
| c !== null && | |
| typeof (c as DistributionSliderComponent).weight === "number" && | |
| typeof (c as DistributionSliderComponent).left === "number" && | |
| typeof (c as DistributionSliderComponent).center === "number" && | |
| typeof (c as DistributionSliderComponent).right === "number" | |
| ); | |
| } | |
| function isValidQuantileComponent(c: unknown): c is DistributionQuantileComponent[number] { | |
| return ( | |
| typeof c === "object" && | |
| c !== null && | |
| "quantile" in c | |
| ); | |
| } | |
| function isClipboardDistribution( | |
| data: unknown | |
| ): data is ClipboardDistribution { | |
| if (!( | |
| typeof data === "object" && | |
| data !== null && | |
| CLIPBOARD_MARKER in data && | |
| (data as ClipboardDistribution)[CLIPBOARD_MARKER] === true && | |
| "type" in data && | |
| "components" in data && | |
| VALID_INPUT_TYPES.includes((data as ClipboardDistribution).type) | |
| )) { | |
| return false; | |
| } | |
| const { type, components } = data as ClipboardDistribution; | |
| if (!Array.isArray(components) || components.length === 0) { | |
| return false; | |
| } | |
| if (type === ContinuousForecastInputType.Slider) { | |
| return components.every(isValidSliderComponent); | |
| } | |
| return components.every(isValidQuantileComponent); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@front_end/src/components/forecast_maker/continuous_input/continuous_clipboard_menu.tsx`
around lines 24 - 36, The isClipboardDistribution type guard currently checks
marker and type but must also validate that (data as
ClipboardDistribution).components is an array and that each component has the
required shape: ensure components is Array.isArray(...) and for each element
verify a discriminant (e.g., component.type or similar) and then for slider
components confirm presence and correct types for weight, left, center, right,
and for quantile components confirm presence and correct type for quantile; keep
referencing CLIPBOARD_MARKER, VALID_INPUT_TYPES and the ClipboardDistribution
shape and update isClipboardDistribution to return false for any malformed
component to prevent downstream runtime errors.
🚀 Preview EnvironmentYour preview environment is ready!
Details
ℹ️ Preview Environment InfoIsolation:
Limitations:
Cleanup:
|
closes #3857
implements copy and paste from arbitrary distributions
support ctrl+c and ctrl+v
Summary by CodeRabbit
New Features
Localization