Skip to main content

excel_mcp_server/types/
inputs.rs

1use schemars::JsonSchema;
2use serde::Deserialize;
3
4use super::enums::*;
5
6// ── Serde default helpers ──────────────────────────────────────────
7
8fn default_chart_width() -> u32 {
9    480
10}
11
12fn default_chart_height() -> u32 {
13    288
14}
15
16fn default_comma() -> String {
17    ",".to_string()
18}
19
20fn default_true() -> bool {
21    true
22}
23
24// ── Workbook lifecycle inputs ──────────────────────────────────────
25
26/// Input for creating a new empty workbook
27#[derive(Deserialize, JsonSchema)]
28#[serde(deny_unknown_fields)]
29pub struct CreateWorkbookInput {}
30
31/// Input for opening an existing Excel file
32#[derive(Deserialize, JsonSchema)]
33#[serde(deny_unknown_fields)]
34pub struct OpenWorkbookInput {
35    /// Absolute or relative path to the Excel file (xlsx, xlsm, xls, ods)
36    pub file_path: String,
37    /// If true, opens in read-only mode using the fast calamine engine.
38    /// If false, opens in edit mode using umya-spreadsheet. Default: false
39    #[serde(default)]
40    pub read_only: bool,
41}
42
43/// Input for saving a workbook to disk
44#[derive(Deserialize, JsonSchema)]
45#[serde(deny_unknown_fields)]
46pub struct SaveWorkbookInput {
47    /// The workbook handle returned by create_workbook or open_workbook
48    pub workbook_id: String,
49    /// Destination file path (must end in .xlsx)
50    pub file_path: String,
51}
52
53/// Input for closing a workbook and freeing memory
54#[derive(Deserialize, JsonSchema)]
55#[serde(deny_unknown_fields)]
56pub struct CloseWorkbookInput {
57    /// The workbook handle to close
58    pub workbook_id: String,
59}
60
61// ── Read inputs ────────────────────────────────────────────────────
62
63/// Input for reading sheet data with optional range and pagination
64#[derive(Deserialize, JsonSchema)]
65#[serde(deny_unknown_fields)]
66pub struct ReadSheetInput {
67    /// The workbook handle
68    pub workbook_id: String,
69    /// Name of the sheet to read
70    pub sheet_name: String,
71    /// Optional range in A1:B2 notation. If omitted, reads the entire used range
72    pub range: Option<String>,
73    /// Continuation token from a previous paginated response
74    pub continuation_token: Option<String>,
75}
76
77/// Input for reading a single cell
78#[derive(Deserialize, JsonSchema)]
79#[serde(deny_unknown_fields)]
80pub struct ReadCellInput {
81    /// The workbook handle
82    pub workbook_id: String,
83    /// Name of the sheet containing the cell
84    pub sheet_name: String,
85    /// Cell reference in A1 notation (e.g., "C5")
86    pub cell: String,
87}
88
89// ── Write inputs ───────────────────────────────────────────────────
90
91/// A single cell write operation
92#[derive(Deserialize, JsonSchema)]
93#[serde(deny_unknown_fields)]
94pub struct CellWrite {
95    /// Cell reference in A1 notation
96    pub cell: String,
97    /// Value to write. Strings starting with "=" are written as formulas.
98    /// Numbers, booleans, and ISO 8601 dates are auto-detected.
99    pub value: serde_json::Value,
100}
101
102/// Input for batch cell writing
103#[derive(Deserialize, JsonSchema)]
104#[serde(deny_unknown_fields)]
105pub struct WriteCellsInput {
106    /// The workbook handle
107    pub workbook_id: String,
108    /// Name of the target sheet
109    pub sheet_name: String,
110    /// Array of cell writes to apply
111    pub cells: Vec<CellWrite>,
112}
113
114/// Input for writing a row of values starting from a cell
115#[derive(Deserialize, JsonSchema)]
116#[serde(deny_unknown_fields)]
117pub struct WriteRowInput {
118    /// The workbook handle
119    pub workbook_id: String,
120    /// Name of the target sheet
121    pub sheet_name: String,
122    /// Starting cell reference (values fill rightward)
123    pub start_cell: String,
124    /// Values to write in consecutive columns
125    pub values: Vec<serde_json::Value>,
126}
127
128/// Input for writing a column of values starting from a cell
129#[derive(Deserialize, JsonSchema)]
130#[serde(deny_unknown_fields)]
131pub struct WriteColumnInput {
132    /// The workbook handle
133    pub workbook_id: String,
134    /// Name of the target sheet
135    pub sheet_name: String,
136    /// Starting cell reference (values fill downward)
137    pub start_cell: String,
138    /// Values to write in consecutive rows
139    pub values: Vec<serde_json::Value>,
140}
141
142// ── Formatting inputs ──────────────────────────────────────────────
143
144/// Input for applying formatting to a range of cells
145#[derive(Deserialize, JsonSchema)]
146#[serde(deny_unknown_fields)]
147pub struct SetCellFormatInput {
148    /// The workbook handle
149    pub workbook_id: String,
150    /// Name of the target sheet
151    pub sheet_name: String,
152    /// Range in A1:B2 notation
153    pub range: String,
154    /// Whether to apply bold font weight
155    #[serde(default)]
156    pub bold: Option<bool>,
157    /// Whether to apply italic font style
158    #[serde(default)]
159    pub italic: Option<bool>,
160    /// Whether to apply underline
161    #[serde(default)]
162    pub underline: Option<bool>,
163    /// Font size in points
164    #[serde(default)]
165    pub font_size: Option<f64>,
166    /// Hex color string for font, e.g., "#FF0000"
167    #[serde(default)]
168    pub font_color: Option<String>,
169    /// Hex color string for cell background
170    #[serde(default)]
171    pub background_color: Option<String>,
172    /// Excel number format string, e.g., "#,##0.00"
173    #[serde(default)]
174    pub number_format: Option<String>,
175    /// Horizontal text alignment
176    #[serde(default)]
177    pub horizontal_alignment: Option<HorizontalAlignment>,
178    /// Vertical text alignment
179    #[serde(default)]
180    pub vertical_alignment: Option<VerticalAlignment>,
181    /// Border style for all edges
182    #[serde(default)]
183    pub border_style: Option<BorderStyle>,
184}
185
186/// Input for merging a range of cells
187#[derive(Deserialize, JsonSchema)]
188#[serde(deny_unknown_fields)]
189pub struct MergeCellsInput {
190    /// The workbook handle
191    pub workbook_id: String,
192    /// Name of the target sheet
193    pub sheet_name: String,
194    /// Range to merge in A1:B2 notation
195    pub range: String,
196}
197
198// ── Chart, image, table inputs ─────────────────────────────────────
199
200/// Input for adding a chart to a worksheet
201#[derive(Deserialize, JsonSchema)]
202#[serde(deny_unknown_fields)]
203pub struct AddChartInput {
204    /// The workbook handle
205    pub workbook_id: String,
206    /// Name of the target sheet
207    pub sheet_name: String,
208    /// Type of chart to create
209    pub chart_type: ChartType,
210    /// Data range in A1:B2 notation
211    pub data_range: String,
212    /// Optional chart title
213    #[serde(default)]
214    pub title: Option<String>,
215    /// Optional X-axis label
216    #[serde(default)]
217    pub x_axis_label: Option<String>,
218    /// Optional Y-axis label
219    #[serde(default)]
220    pub y_axis_label: Option<String>,
221    /// Position of the chart legend
222    #[serde(default)]
223    pub legend_position: Option<LegendPosition>,
224    /// Chart width in pixels. Default: 480
225    #[serde(default = "default_chart_width")]
226    pub width: u32,
227    /// Chart height in pixels. Default: 288
228    #[serde(default = "default_chart_height")]
229    pub height: u32,
230}
231
232/// Input for embedding an image in a worksheet
233#[derive(Deserialize, JsonSchema)]
234#[serde(deny_unknown_fields)]
235pub struct AddImageInput {
236    /// The workbook handle
237    pub workbook_id: String,
238    /// Name of the target sheet
239    pub sheet_name: String,
240    /// Cell where the image top-left corner is anchored
241    pub cell: String,
242    /// Path to a PNG or JPEG image file
243    pub image_path: String,
244    /// Optional width in pixels to scale the image
245    #[serde(default)]
246    pub width: Option<u32>,
247    /// Optional height in pixels to scale the image
248    #[serde(default)]
249    pub height: Option<u32>,
250}
251
252/// Input for creating an Excel Table
253#[derive(Deserialize, JsonSchema)]
254#[serde(deny_unknown_fields)]
255pub struct AddTableInput {
256    /// The workbook handle
257    pub workbook_id: String,
258    /// Name of the target sheet
259    pub sheet_name: String,
260    /// Range for the table in A1:B2 notation (includes header row)
261    pub range: String,
262    /// Column header names
263    pub columns: Vec<String>,
264    /// Optional Excel table style name (e.g., "Table Style Medium 2")
265    #[serde(default)]
266    pub style: Option<String>,
267    /// Whether to show a totals row. Default: false
268    #[serde(default)]
269    pub totals_row: bool,
270    /// Whether to enable autofilter. Default: true
271    #[serde(default = "default_true")]
272    pub autofilter: bool,
273}
274
275// ── Conditional formatting, validation, sparkline inputs ───────────
276
277/// Input for adding a conditional formatting rule
278#[derive(Deserialize, JsonSchema)]
279#[serde(deny_unknown_fields)]
280pub struct AddConditionalFormatInput {
281    /// The workbook handle
282    pub workbook_id: String,
283    /// Name of the target sheet
284    pub sheet_name: String,
285    /// Range to apply the rule to in A1:B2 notation
286    pub range: String,
287    /// The conditional formatting rule definition
288    pub rule: ConditionalFormatRule,
289    /// Formatting to apply when condition is met
290    #[serde(default)]
291    pub format: Option<ConditionalFormatStyle>,
292}
293
294/// Input for adding data validation to a range
295#[derive(Deserialize, JsonSchema)]
296#[serde(deny_unknown_fields)]
297pub struct AddDataValidationInput {
298    /// The workbook handle
299    pub workbook_id: String,
300    /// Name of the target sheet
301    pub sheet_name: String,
302    /// Range to apply validation to in A1:B2 notation
303    pub range: String,
304    /// The validation rule definition
305    pub validation: ValidationRule,
306    /// Optional input message shown when the cell is selected
307    #[serde(default)]
308    pub input_message: Option<ValidationMessage>,
309    /// Optional error alert shown when invalid data is entered
310    #[serde(default)]
311    pub error_alert: Option<ValidationAlert>,
312}
313
314// ── Layout inputs ──────────────────────────────────────────────────
315
316/// Input for setting the width of a column
317#[derive(Deserialize, JsonSchema)]
318#[serde(deny_unknown_fields)]
319pub struct SetColumnWidthInput {
320    /// The workbook handle
321    pub workbook_id: String,
322    /// Name of the target sheet
323    pub sheet_name: String,
324    /// Column identifier in letter notation (e.g., "A", "BC")
325    pub column: String,
326    /// Width in character units
327    pub width: f64,
328}
329
330/// Input for setting the height of a row
331#[derive(Deserialize, JsonSchema)]
332#[serde(deny_unknown_fields)]
333pub struct SetRowHeightInput {
334    /// The workbook handle
335    pub workbook_id: String,
336    /// Name of the target sheet
337    pub sheet_name: String,
338    /// 1-based row number
339    pub row: u32,
340    /// Height in points
341    pub height: f64,
342}
343
344/// Input for freezing panes at a cell position
345#[derive(Deserialize, JsonSchema)]
346#[serde(deny_unknown_fields)]
347pub struct FreezePanesInput {
348    /// The workbook handle
349    pub workbook_id: String,
350    /// Name of the target sheet
351    pub sheet_name: String,
352    /// Cell reference — rows above and columns left of this cell are frozen
353    pub cell: String,
354}
355
356/// Input for adding a sparkline to a cell
357#[derive(Deserialize, JsonSchema)]
358#[serde(deny_unknown_fields)]
359pub struct AddSparklineInput {
360    /// The workbook handle
361    pub workbook_id: String,
362    /// Name of the target sheet
363    pub sheet_name: String,
364    /// Cell where the sparkline is placed
365    pub target_cell: String,
366    /// Data range for the sparkline values
367    pub data_range: String,
368    /// Type of sparkline to create
369    pub sparkline_type: SparklineType,
370}
371
372// ── Search and export inputs ───────────────────────────────────────
373
374/// Input for searching cell values across sheets
375#[derive(Deserialize, JsonSchema)]
376#[serde(deny_unknown_fields)]
377pub struct SearchCellsInput {
378    /// The workbook handle
379    pub workbook_id: String,
380    /// If omitted, searches all sheets
381    #[serde(default)]
382    pub sheet_name: Option<String>,
383    /// The value or substring to search for
384    pub query: String,
385    /// Search mode: exact or substring. Default: substring
386    #[serde(default)]
387    pub match_mode: MatchMode,
388}
389
390/// Input for exporting a sheet as CSV
391#[derive(Deserialize, JsonSchema)]
392#[serde(deny_unknown_fields)]
393pub struct SheetToCsvInput {
394    /// The workbook handle
395    pub workbook_id: String,
396    /// Name of the sheet to export
397    pub sheet_name: String,
398    /// Delimiter character. Default: ","
399    #[serde(default = "default_comma")]
400    pub delimiter: String,
401}
402
403// ── Sheet management inputs ────────────────────────────────────────
404
405/// Input for adding a new worksheet
406#[derive(Deserialize, JsonSchema)]
407#[serde(deny_unknown_fields)]
408pub struct AddSheetInput {
409    /// The workbook handle
410    pub workbook_id: String,
411    /// Name for the new sheet
412    pub sheet_name: String,
413}
414
415/// Input for renaming an existing worksheet
416#[derive(Deserialize, JsonSchema)]
417#[serde(deny_unknown_fields)]
418pub struct RenameSheetInput {
419    /// The workbook handle
420    pub workbook_id: String,
421    /// Current name of the sheet to rename
422    pub current_name: String,
423    /// New name for the sheet
424    pub new_name: String,
425}
426
427/// Input for deleting a worksheet
428#[derive(Deserialize, JsonSchema)]
429#[serde(deny_unknown_fields)]
430pub struct DeleteSheetInput {
431    /// The workbook handle
432    pub workbook_id: String,
433    /// Name of the sheet to delete
434    pub sheet_name: String,
435}
436
437/// Input for listing all sheets in a workbook
438#[derive(Deserialize, JsonSchema)]
439#[serde(deny_unknown_fields)]
440pub struct ListSheetsInput {
441    /// The workbook handle
442    pub workbook_id: String,
443}
444
445/// Input for getting the dimensions of a sheet
446#[derive(Deserialize, JsonSchema)]
447#[serde(deny_unknown_fields)]
448pub struct GetSheetDimensionsInput {
449    /// The workbook handle
450    pub workbook_id: String,
451    /// Name of the sheet to measure
452    pub sheet_name: String,
453}
454
455/// Input for describing a workbook's structure and sample data
456#[derive(Deserialize, JsonSchema)]
457#[serde(deny_unknown_fields)]
458pub struct DescribeWorkbookInput {
459    /// The workbook handle
460    pub workbook_id: String,
461}
462
463// ── New tools: Batch 1–4 ───────────────────────────────────────────
464
465/// Margins for page setup (inches)
466#[derive(Deserialize, JsonSchema)]
467pub struct PageMargins {
468    #[serde(default)]
469    pub top: Option<f64>,
470    #[serde(default)]
471    pub bottom: Option<f64>,
472    #[serde(default)]
473    pub left: Option<f64>,
474    #[serde(default)]
475    pub right: Option<f64>,
476}
477
478/// Fit-to-page settings
479#[derive(Deserialize, JsonSchema)]
480pub struct FitToPages {
481    pub width: u16,
482    pub height: u16,
483}
484
485/// Repeat rows for printing
486#[derive(Deserialize, JsonSchema)]
487pub struct RepeatRows {
488    /// First row (0-based)
489    pub first: u32,
490    /// Last row (0-based)
491    pub last: u32,
492}
493
494/// Input for configuring page setup, headers, footers, print options
495#[derive(Deserialize, JsonSchema)]
496#[serde(deny_unknown_fields)]
497pub struct SetPageSetupInput {
498    pub workbook_id: String,
499    pub sheet_name: String,
500    #[serde(default)]
501    pub landscape: Option<bool>,
502    #[serde(default)]
503    pub paper_size: Option<u8>,
504    #[serde(default)]
505    pub margins: Option<PageMargins>,
506    #[serde(default)]
507    pub fit_to_pages: Option<FitToPages>,
508    #[serde(default)]
509    pub print_scale: Option<u16>,
510    /// Print area in A1:B2 notation
511    #[serde(default)]
512    pub print_area: Option<String>,
513    #[serde(default)]
514    pub repeat_rows: Option<RepeatRows>,
515    /// Excel header string (supports &L, &C, &R, &P, &N, &D codes)
516    #[serde(default)]
517    pub header: Option<String>,
518    /// Excel footer string
519    #[serde(default)]
520    pub footer: Option<String>,
521    #[serde(default)]
522    pub print_gridlines: Option<bool>,
523    #[serde(default)]
524    pub center_horizontally: Option<bool>,
525    #[serde(default)]
526    pub center_vertically: Option<bool>,
527}
528
529/// Input for adding a comment/note to a cell
530#[derive(Deserialize, JsonSchema)]
531#[serde(deny_unknown_fields)]
532pub struct AddCommentInput {
533    pub workbook_id: String,
534    pub sheet_name: String,
535    pub cell: String,
536    pub text: String,
537    #[serde(default)]
538    pub author: Option<String>,
539}
540
541/// Input for adding a hyperlink to a cell
542#[derive(Deserialize, JsonSchema)]
543#[serde(deny_unknown_fields)]
544pub struct AddHyperlinkInput {
545    pub workbook_id: String,
546    pub sheet_name: String,
547    pub cell: String,
548    pub url: String,
549    #[serde(default)]
550    pub tooltip: Option<String>,
551    /// Display text (if different from URL)
552    #[serde(default)]
553    pub display_text: Option<String>,
554}
555
556/// Input for adding a defined name (named range)
557#[derive(Deserialize, JsonSchema)]
558#[serde(deny_unknown_fields)]
559pub struct AddDefinedNameInput {
560    pub workbook_id: String,
561    pub name: String,
562    /// Formula or range reference, e.g. "Sheet1!$A$1:$B$10"
563    pub formula: String,
564}
565
566/// Input for listing defined names
567#[derive(Deserialize, JsonSchema)]
568#[serde(deny_unknown_fields)]
569pub struct ListDefinedNamesInput {
570    pub workbook_id: String,
571}
572
573/// Input for sheet display settings
574#[derive(Deserialize, JsonSchema)]
575#[serde(deny_unknown_fields)]
576pub struct SetSheetSettingsInput {
577    pub workbook_id: String,
578    pub sheet_name: String,
579    #[serde(default)]
580    pub hidden: Option<bool>,
581    #[serde(default)]
582    pub very_hidden: Option<bool>,
583    #[serde(default)]
584    pub zoom: Option<u16>,
585    #[serde(default)]
586    pub hide_gridlines: Option<bool>,
587    #[serde(default)]
588    pub hide_headings: Option<bool>,
589    #[serde(default)]
590    pub tab_color: Option<String>,
591    #[serde(default)]
592    pub right_to_left: Option<bool>,
593}
594
595/// Input for setting the active (visible) sheet
596#[derive(Deserialize, JsonSchema)]
597#[serde(deny_unknown_fields)]
598pub struct SetActiveSheetInput {
599    pub workbook_id: String,
600    /// 0-based sheet index
601    pub sheet_index: usize,
602}
603
604/// Input for inserting/deleting rows
605#[derive(Deserialize, JsonSchema)]
606#[serde(deny_unknown_fields)]
607pub struct InsertDeleteRowsInput {
608    pub workbook_id: String,
609    pub sheet_name: String,
610    /// 1-based row number where insertion/deletion starts
611    pub at_row: u32,
612    /// Number of rows to insert or delete
613    pub count: u32,
614}
615
616/// Input for inserting/deleting columns
617#[derive(Deserialize, JsonSchema)]
618#[serde(deny_unknown_fields)]
619pub struct InsertDeleteColumnsInput {
620    pub workbook_id: String,
621    pub sheet_name: String,
622    /// Column letter where insertion/deletion starts (e.g. "C")
623    pub at_column: String,
624    pub count: u16,
625}
626
627/// Input for grouping rows or columns (outline)
628#[derive(Deserialize, JsonSchema)]
629#[serde(deny_unknown_fields)]
630pub struct GroupRowsInput {
631    pub workbook_id: String,
632    pub sheet_name: String,
633    /// First row (1-based)
634    pub start: u32,
635    /// Last row (1-based)
636    pub end: u32,
637    /// Outline level (1-7). Default: 1
638    #[serde(default = "default_level")]
639    pub level: u8,
640}
641
642/// Input for grouping columns
643#[derive(Deserialize, JsonSchema)]
644#[serde(deny_unknown_fields)]
645pub struct GroupColumnsInput {
646    pub workbook_id: String,
647    pub sheet_name: String,
648    /// First column letter
649    pub start: String,
650    /// Last column letter
651    pub end: String,
652    #[serde(default = "default_level")]
653    pub level: u8,
654}
655
656fn default_level() -> u8 {
657    1
658}
659
660/// Input for protecting a sheet
661#[derive(Deserialize, JsonSchema)]
662#[serde(deny_unknown_fields)]
663pub struct ProtectSheetInput {
664    pub workbook_id: String,
665    pub sheet_name: String,
666    #[serde(default)]
667    pub password: Option<String>,
668}
669
670/// Input for protecting a workbook
671#[derive(Deserialize, JsonSchema)]
672#[serde(deny_unknown_fields)]
673pub struct ProtectWorkbookInput {
674    pub workbook_id: String,
675    #[serde(default)]
676    pub password: Option<String>,
677}
678
679/// Input for autofitting column widths
680#[derive(Deserialize, JsonSchema)]
681#[serde(deny_unknown_fields)]
682pub struct AutofitColumnsInput {
683    pub workbook_id: String,
684    pub sheet_name: String,
685}
686
687/// A single chart series definition
688#[derive(Deserialize, JsonSchema)]
689pub struct ChartSeriesInput {
690    /// Data range for values (e.g. "Sheet1!$B$2:$B$10")
691    pub values: String,
692    /// Data range for categories/labels
693    #[serde(default)]
694    pub categories: Option<String>,
695    /// Series name
696    #[serde(default)]
697    pub name: Option<String>,
698    /// Hex color for the series
699    #[serde(default)]
700    pub color: Option<String>,
701    /// Show data labels on this series
702    #[serde(default)]
703    pub data_labels: Option<bool>,
704    /// Trendline type: linear, exponential, polynomial, power, logarithmic, moving_average
705    #[serde(default)]
706    pub trendline: Option<String>,
707    /// Marker type: circle, diamond, square, triangle, none
708    #[serde(default)]
709    pub marker: Option<String>,
710    /// Use secondary Y axis
711    #[serde(default)]
712    pub secondary_axis: Option<bool>,
713}
714
715/// Pivot chart source
716#[derive(Deserialize, JsonSchema)]
717pub struct PivotChartSourceInput {
718    pub pivot_table: String,
719    pub sheet: String,
720}
721
722/// Enhanced chart input with full series control
723#[derive(Deserialize, JsonSchema)]
724#[serde(deny_unknown_fields)]
725pub struct AddChartEnhancedInput {
726    pub workbook_id: String,
727    pub sheet_name: String,
728    pub chart_type: ChartType,
729    /// Individual series definitions (preferred over data_range)
730    #[serde(default)]
731    pub series: Vec<ChartSeriesInput>,
732    /// Simple data range (used if series is empty)
733    #[serde(default)]
734    pub data_range: Option<String>,
735    /// Cell where chart top-left is placed (e.g. "E2"). Default: "A1"
736    #[serde(default)]
737    pub cell: Option<String>,
738    #[serde(default)]
739    pub title: Option<String>,
740    #[serde(default)]
741    pub x_axis_label: Option<String>,
742    #[serde(default)]
743    pub y_axis_label: Option<String>,
744    #[serde(default)]
745    pub legend_position: Option<LegendPosition>,
746    #[serde(default = "default_chart_width")]
747    pub width: u32,
748    #[serde(default = "default_chart_height")]
749    pub height: u32,
750    /// Link chart to a pivot table
751    #[serde(default)]
752    pub pivot_source: Option<PivotChartSourceInput>,
753}
754
755/// Pivot table value field
756#[derive(Deserialize, JsonSchema)]
757pub struct PivotValueFieldInput {
758    pub field: String,
759    /// Aggregation: sum, count, average, max, min, product, count_nums, std_dev, var
760    #[serde(default = "default_sum")]
761    pub aggregation: String,
762}
763
764fn default_sum() -> String {
765    "sum".to_string()
766}
767
768/// Input for creating a pivot table
769#[derive(Deserialize, JsonSchema)]
770#[serde(deny_unknown_fields)]
771pub struct AddPivotTableInput {
772    pub workbook_id: String,
773    pub sheet_name: String,
774    /// Cell where pivot table starts (e.g. "A1")
775    #[serde(default)]
776    pub cell: Option<String>,
777    pub name: String,
778    /// Source range including sheet (e.g. "'Data'!$A$1:$E$100")
779    pub source_range: String,
780    #[serde(default)]
781    pub row_fields: Vec<String>,
782    #[serde(default)]
783    pub column_fields: Vec<String>,
784    pub value_fields: Vec<PivotValueFieldInput>,
785    #[serde(default)]
786    pub filter_fields: Vec<String>,
787    #[serde(default)]
788    pub style: Option<String>,
789    /// Layout: compact, outline, tabular. Default: compact
790    #[serde(default)]
791    pub layout: Option<String>,
792}
793
794/// Input for reading comments from a sheet
795#[derive(Deserialize, JsonSchema)]
796#[serde(deny_unknown_fields)]
797pub struct ReadCommentsInput {
798    pub workbook_id: String,
799    pub sheet_name: String,
800}
801
802/// A rich text run
803#[derive(Deserialize, JsonSchema)]
804pub struct RichTextRunInput {
805    pub text: String,
806    #[serde(default)]
807    pub bold: Option<bool>,
808    #[serde(default)]
809    pub italic: Option<bool>,
810    #[serde(default)]
811    pub color: Option<String>,
812    #[serde(default)]
813    pub font_size: Option<f64>,
814}
815
816/// Input for writing rich text to a cell
817#[derive(Deserialize, JsonSchema)]
818#[serde(deny_unknown_fields)]
819pub struct WriteRichTextInput {
820    pub workbook_id: String,
821    pub sheet_name: String,
822    pub cell: String,
823    pub runs: Vec<RichTextRunInput>,
824}
825
826// ── Batch 5–8: Remaining 22 tools ──────────────────────────────────
827
828/// Input for setting column/row format
829#[derive(Deserialize, JsonSchema)]
830#[serde(deny_unknown_fields)]
831pub struct SetColumnFormatInput {
832    pub workbook_id: String,
833    pub sheet_name: String,
834    pub column: String,
835    #[serde(default)]
836    pub bold: Option<bool>,
837    #[serde(default)]
838    pub italic: Option<bool>,
839    #[serde(default)]
840    pub font_size: Option<f64>,
841    #[serde(default)]
842    pub font_color: Option<String>,
843    #[serde(default)]
844    pub background_color: Option<String>,
845    #[serde(default)]
846    pub number_format: Option<String>,
847}
848
849#[derive(Deserialize, JsonSchema)]
850#[serde(deny_unknown_fields)]
851pub struct SetRowFormatInput {
852    pub workbook_id: String,
853    pub sheet_name: String,
854    /// 1-based row number
855    pub row: u32,
856    #[serde(default)]
857    pub bold: Option<bool>,
858    #[serde(default)]
859    pub italic: Option<bool>,
860    #[serde(default)]
861    pub font_size: Option<f64>,
862    #[serde(default)]
863    pub font_color: Option<String>,
864    #[serde(default)]
865    pub background_color: Option<String>,
866    #[serde(default)]
867    pub number_format: Option<String>,
868}
869
870#[derive(Deserialize, JsonSchema)]
871#[serde(deny_unknown_fields)]
872pub struct SetColumnHiddenInput {
873    pub workbook_id: String,
874    pub sheet_name: String,
875    pub column: String,
876    #[serde(default)]
877    pub hidden: bool,
878}
879
880#[derive(Deserialize, JsonSchema)]
881#[serde(deny_unknown_fields)]
882pub struct SetRowHiddenInput {
883    pub workbook_id: String,
884    pub sheet_name: String,
885    pub row: u32,
886    #[serde(default)]
887    pub hidden: bool,
888}
889
890#[derive(Deserialize, JsonSchema)]
891#[serde(deny_unknown_fields)]
892pub struct SetColumnRangeWidthInput {
893    pub workbook_id: String,
894    pub sheet_name: String,
895    pub first_column: String,
896    pub last_column: String,
897    pub width: f64,
898}
899
900#[derive(Deserialize, JsonSchema)]
901#[serde(deny_unknown_fields)]
902pub struct SetDefaultRowHeightInput {
903    pub workbook_id: String,
904    pub sheet_name: String,
905    pub height: f64,
906}
907
908#[derive(Deserialize, JsonSchema)]
909#[serde(deny_unknown_fields)]
910pub struct SetSelectionInput {
911    pub workbook_id: String,
912    pub sheet_name: String,
913    pub cell: String,
914}
915
916#[derive(Deserialize, JsonSchema)]
917#[serde(deny_unknown_fields)]
918pub struct SetAutofilterInput {
919    pub workbook_id: String,
920    pub sheet_name: String,
921    /// Range in A1:B2 notation
922    pub range: String,
923}
924
925#[derive(Deserialize, JsonSchema)]
926#[serde(deny_unknown_fields)]
927pub struct FilterColumnInput {
928    pub workbook_id: String,
929    pub sheet_name: String,
930    pub column: String,
931    pub values: Vec<String>,
932}
933
934#[derive(Deserialize, JsonSchema)]
935#[serde(deny_unknown_fields)]
936pub struct IgnoreErrorInput {
937    pub workbook_id: String,
938    pub sheet_name: String,
939    /// Error type: "number_stored_as_text", "formula_range", etc.
940    pub error_type: String,
941    /// Range in A1:B2 notation
942    pub range: String,
943}
944
945#[derive(Deserialize, JsonSchema)]
946#[serde(deny_unknown_fields)]
947pub struct SetPageBreaksInput {
948    pub workbook_id: String,
949    pub sheet_name: String,
950    #[serde(default)]
951    pub row_breaks: Vec<u32>,
952    #[serde(default)]
953    pub col_breaks: Vec<u16>,
954}
955
956#[derive(Deserialize, JsonSchema)]
957#[serde(deny_unknown_fields)]
958pub struct UnprotectRangeInput {
959    pub workbook_id: String,
960    pub sheet_name: String,
961    pub range: String,
962    pub title: String,
963    #[serde(default)]
964    pub password: Option<String>,
965}
966
967#[derive(Deserialize, JsonSchema)]
968#[serde(deny_unknown_fields)]
969pub struct WriteFormulaInput {
970    pub workbook_id: String,
971    pub sheet_name: String,
972    pub cell: String,
973    pub formula: String,
974    /// Optional cached numeric result
975    #[serde(default)]
976    pub cached_result: Option<f64>,
977}
978
979#[derive(Deserialize, JsonSchema)]
980#[serde(deny_unknown_fields)]
981pub struct WriteArrayFormulaInput {
982    pub workbook_id: String,
983    pub sheet_name: String,
984    /// Range the array formula spans (e.g. "A1:C3")
985    pub range: String,
986    pub formula: String,
987}
988
989#[derive(Deserialize, JsonSchema)]
990#[serde(deny_unknown_fields)]
991pub struct WriteDynamicFormulaInput {
992    pub workbook_id: String,
993    pub sheet_name: String,
994    pub cell: String,
995    pub formula: String,
996}
997
998#[derive(Deserialize, JsonSchema)]
999#[serde(deny_unknown_fields)]
1000pub struct WriteBlankInput {
1001    pub workbook_id: String,
1002    pub sheet_name: String,
1003    pub cell: String,
1004    #[serde(default)]
1005    pub bold: Option<bool>,
1006    #[serde(default)]
1007    pub background_color: Option<String>,
1008    #[serde(default)]
1009    pub number_format: Option<String>,
1010}
1011
1012#[derive(Deserialize, JsonSchema)]
1013#[serde(deny_unknown_fields)]
1014pub struct ClearCellInput {
1015    pub workbook_id: String,
1016    pub sheet_name: String,
1017    pub cell: String,
1018}
1019
1020#[derive(Deserialize, JsonSchema)]
1021#[serde(deny_unknown_fields)]
1022pub struct SetCalcModeInput {
1023    pub workbook_id: String,
1024    /// "auto", "manual", or "auto_no_table"
1025    pub mode: String,
1026}
1027
1028#[derive(Deserialize, JsonSchema)]
1029#[serde(deny_unknown_fields)]
1030pub struct SetPropertiesInput {
1031    pub workbook_id: String,
1032    #[serde(default)]
1033    pub title: Option<String>,
1034    #[serde(default)]
1035    pub author: Option<String>,
1036    #[serde(default)]
1037    pub subject: Option<String>,
1038    #[serde(default)]
1039    pub company: Option<String>,
1040    #[serde(default)]
1041    pub description: Option<String>,
1042}
1043
1044#[derive(Deserialize, JsonSchema)]
1045#[serde(deny_unknown_fields)]
1046pub struct MoveWorksheetInput {
1047    pub workbook_id: String,
1048    pub sheet_name: String,
1049    /// 0-based target position
1050    pub to_index: usize,
1051}
1052
1053#[derive(Deserialize, JsonSchema)]
1054#[serde(deny_unknown_fields)]
1055pub struct WriteInternalLinkInput {
1056    pub workbook_id: String,
1057    pub sheet_name: String,
1058    pub cell: String,
1059    /// Internal location (e.g. "Sheet2!A1")
1060    pub location: String,
1061    pub display_text: String,
1062}
1063
1064// ══════════════════════════════════════════════════════════════════
1065// Consolidated input types (replacing multiple separate inputs)
1066// ══════════════════════════════════════════════════════════════════
1067
1068#[derive(Deserialize, JsonSchema)]
1069#[serde(deny_unknown_fields)]
1070pub struct ConfigureWorkbookInput {
1071    pub workbook_id: String,
1072    /// "auto", "manual", or "auto_no_table"
1073    #[serde(default)]
1074    pub calc_mode: Option<String>,
1075    /// 0-based sheet index to make active
1076    #[serde(default)]
1077    pub active_sheet: Option<usize>,
1078    #[serde(default)]
1079    pub title: Option<String>,
1080    #[serde(default)]
1081    pub author: Option<String>,
1082    #[serde(default)]
1083    pub subject: Option<String>,
1084    #[serde(default)]
1085    pub company: Option<String>,
1086    #[serde(default)]
1087    pub description: Option<String>,
1088}
1089
1090#[derive(Deserialize, JsonSchema)]
1091#[serde(deny_unknown_fields)]
1092pub struct ModifyRowsInput {
1093    pub workbook_id: String,
1094    pub sheet_name: String,
1095    /// "insert" or "delete"
1096    pub action: String,
1097    /// 1-based row number
1098    pub at_row: u32,
1099    pub count: u32,
1100}
1101
1102#[derive(Deserialize, JsonSchema)]
1103#[serde(deny_unknown_fields)]
1104pub struct ModifyColumnsInput {
1105    pub workbook_id: String,
1106    pub sheet_name: String,
1107    /// "insert" or "delete"
1108    pub action: String,
1109    pub at_column: String,
1110    pub count: u16,
1111}
1112
1113#[derive(Deserialize, JsonSchema)]
1114#[serde(deny_unknown_fields)]
1115pub struct WriteFormulaConsolidatedInput {
1116    pub workbook_id: String,
1117    pub sheet_name: String,
1118    /// Cell for regular/dynamic, or range for array (e.g. "A1" or "A1:C3")
1119    pub cell: String,
1120    pub formula: String,
1121    /// "regular" (default), "array", or "dynamic"
1122    #[serde(default)]
1123    pub formula_type: Option<String>,
1124    #[serde(default)]
1125    pub cached_result: Option<f64>,
1126}
1127
1128#[derive(Deserialize, JsonSchema)]
1129#[serde(deny_unknown_fields)]
1130pub struct ManageCellInput {
1131    pub workbook_id: String,
1132    pub sheet_name: String,
1133    pub cell: String,
1134    /// "blank" or "clear"
1135    pub action: String,
1136    #[serde(default)]
1137    pub background_color: Option<String>,
1138    #[serde(default)]
1139    pub number_format: Option<String>,
1140}
1141
1142#[derive(Deserialize, JsonSchema)]
1143#[serde(deny_unknown_fields)]
1144pub struct ManageCommentsInput {
1145    pub workbook_id: String,
1146    pub sheet_name: String,
1147    /// "add" or "read"
1148    pub action: String,
1149    #[serde(default)]
1150    pub cell: Option<String>,
1151    #[serde(default)]
1152    pub text: Option<String>,
1153    #[serde(default)]
1154    pub author: Option<String>,
1155}
1156
1157#[derive(Deserialize, JsonSchema)]
1158#[serde(deny_unknown_fields)]
1159pub struct ManageDefinedNamesInput {
1160    pub workbook_id: String,
1161    /// "add" or "list"
1162    pub action: String,
1163    #[serde(default)]
1164    pub name: Option<String>,
1165    #[serde(default)]
1166    pub formula: Option<String>,
1167}
1168
1169#[derive(Deserialize, JsonSchema)]
1170#[serde(deny_unknown_fields)]
1171pub struct AddLinkInput {
1172    pub workbook_id: String,
1173    pub sheet_name: String,
1174    pub cell: String,
1175    /// "url" or "internal"
1176    #[serde(default = "default_url")]
1177    pub link_type: String,
1178    /// URL for external, or "Sheet2!A1" for internal
1179    pub target: String,
1180    #[serde(default)]
1181    pub display_text: Option<String>,
1182    #[serde(default)]
1183    pub tooltip: Option<String>,
1184}
1185
1186fn default_url() -> String {
1187    "url".to_string()
1188}
1189
1190#[derive(Deserialize, JsonSchema)]
1191#[serde(deny_unknown_fields)]
1192pub struct ProtectInput {
1193    pub workbook_id: String,
1194    /// "sheet", "workbook", or "unprotect_range"
1195    pub target: String,
1196    #[serde(default)]
1197    pub sheet_name: Option<String>,
1198    #[serde(default)]
1199    pub password: Option<String>,
1200    /// For unprotect_range: the range to allow editing
1201    #[serde(default)]
1202    pub range: Option<String>,
1203    /// For unprotect_range: title for the range
1204    #[serde(default)]
1205    pub range_title: Option<String>,
1206}
1207
1208#[derive(Deserialize, JsonSchema)]
1209#[serde(deny_unknown_fields)]
1210pub struct SetDimensionsInput {
1211    pub workbook_id: String,
1212    pub sheet_name: String,
1213    /// "column_width", "row_height", "column_range_width", or "default_row_height"
1214    pub target: String,
1215    #[serde(default)]
1216    pub column: Option<String>,
1217    #[serde(default)]
1218    pub first_column: Option<String>,
1219    #[serde(default)]
1220    pub last_column: Option<String>,
1221    /// 1-based row number
1222    #[serde(default)]
1223    pub row: Option<u32>,
1224    pub value: f64,
1225}
1226
1227#[derive(Deserialize, JsonSchema)]
1228#[serde(deny_unknown_fields)]
1229pub struct SetVisibilityInput {
1230    pub workbook_id: String,
1231    pub sheet_name: String,
1232    /// "row" or "column"
1233    pub target: String,
1234    /// Column letter (for column) or 1-based row number as string (for row)
1235    pub identifier: String,
1236    pub hidden: bool,
1237}
1238
1239#[derive(Deserialize, JsonSchema)]
1240#[serde(deny_unknown_fields)]
1241pub struct SetRowColumnFormatInput {
1242    pub workbook_id: String,
1243    pub sheet_name: String,
1244    /// "row" or "column"
1245    pub target: String,
1246    /// Column letter or 1-based row number as string
1247    pub identifier: String,
1248    #[serde(default)]
1249    pub bold: Option<bool>,
1250    #[serde(default)]
1251    pub italic: Option<bool>,
1252    #[serde(default)]
1253    pub font_size: Option<f64>,
1254    #[serde(default)]
1255    pub font_color: Option<String>,
1256    #[serde(default)]
1257    pub background_color: Option<String>,
1258    #[serde(default)]
1259    pub number_format: Option<String>,
1260}
1261
1262#[derive(Deserialize, JsonSchema)]
1263#[serde(deny_unknown_fields)]
1264pub struct GroupInput {
1265    pub workbook_id: String,
1266    pub sheet_name: String,
1267    /// "rows" or "columns"
1268    pub target: String,
1269    /// For rows: 1-based row numbers. For columns: column letters.
1270    pub start: String,
1271    pub end: String,
1272    #[serde(default = "default_level")]
1273    pub level: u8,
1274}
1275
1276#[derive(Deserialize, JsonSchema)]
1277#[serde(deny_unknown_fields)]
1278pub struct ManageAutofilterInput {
1279    pub workbook_id: String,
1280    pub sheet_name: String,
1281    /// Range in A1:B2 notation (sets autofilter)
1282    pub range: String,
1283    /// Optional: column letter to filter
1284    #[serde(default)]
1285    pub filter_column: Option<String>,
1286    /// Optional: filter values for the column
1287    #[serde(default)]
1288    pub filter_values: Option<Vec<String>>,
1289}
1290
1291// ── Batch 9: Feature-parity tools ──────────────────────────────────
1292
1293/// A single data point for a waterfall chart
1294#[derive(Deserialize, JsonSchema)]
1295pub struct WaterfallPoint {
1296    pub category: String,
1297    pub value: f64,
1298    /// "increase", "decrease", or "total"
1299    pub point_type: WaterfallPointKind,
1300}
1301
1302/// Input for adding a waterfall chart (Excel 2016+ ChartEx format)
1303#[derive(Deserialize, JsonSchema)]
1304#[serde(deny_unknown_fields)]
1305pub struct AddWaterfallChartInput {
1306    pub workbook_id: String,
1307    pub sheet_name: String,
1308    #[serde(default)]
1309    pub title: Option<String>,
1310    #[serde(default)]
1311    pub series_name: Option<String>,
1312    /// Data points for the waterfall chart
1313    pub points: Vec<WaterfallPoint>,
1314    /// Chart width in pixels. Default: 480
1315    #[serde(default = "default_chart_width")]
1316    pub width: u32,
1317    /// Chart height in pixels. Default: 288
1318    #[serde(default = "default_chart_height")]
1319    pub height: u32,
1320    /// Anchor cell for the chart. Default: "A1"
1321    #[serde(default)]
1322    pub cell: Option<String>,
1323}
1324
1325/// A single data point for a funnel chart
1326#[derive(Deserialize, JsonSchema)]
1327pub struct FunnelPoint {
1328    pub category: String,
1329    pub value: f64,
1330}
1331
1332/// Input for adding a funnel chart (Excel 2016+ ChartEx format)
1333#[derive(Deserialize, JsonSchema)]
1334#[serde(deny_unknown_fields)]
1335pub struct AddFunnelChartInput {
1336    pub workbook_id: String,
1337    pub sheet_name: String,
1338    #[serde(default)]
1339    pub title: Option<String>,
1340    #[serde(default)]
1341    pub series_name: Option<String>,
1342    /// Data points for the funnel chart
1343    pub points: Vec<FunnelPoint>,
1344    /// Chart width in pixels. Default: 480
1345    #[serde(default = "default_chart_width")]
1346    pub width: u32,
1347    /// Chart height in pixels. Default: 288
1348    #[serde(default = "default_chart_height")]
1349    pub height: u32,
1350    /// Anchor cell for the chart. Default: "A1"
1351    #[serde(default)]
1352    pub cell: Option<String>,
1353}
1354
1355/// A single data point for a treemap chart
1356#[derive(Deserialize, JsonSchema)]
1357pub struct TreemapPoint {
1358    pub category: String,
1359    pub value: f64,
1360    /// Optional hex color (e.g. "#FF0000")
1361    #[serde(default)]
1362    pub color: Option<String>,
1363}
1364
1365/// Input for adding a treemap chart (Excel 2016+ ChartEx format)
1366#[derive(Deserialize, JsonSchema)]
1367#[serde(deny_unknown_fields)]
1368pub struct AddTreemapChartInput {
1369    pub workbook_id: String,
1370    pub sheet_name: String,
1371    #[serde(default)]
1372    pub title: Option<String>,
1373    #[serde(default)]
1374    pub series_name: Option<String>,
1375    /// Data points for the treemap chart
1376    pub points: Vec<TreemapPoint>,
1377    /// Chart width in pixels. Default: 480
1378    #[serde(default = "default_chart_width")]
1379    pub width: u32,
1380    /// Chart height in pixels. Default: 288
1381    #[serde(default = "default_chart_height")]
1382    pub height: u32,
1383    /// Anchor cell for the chart. Default: "A1"
1384    #[serde(default)]
1385    pub cell: Option<String>,
1386}
1387
1388/// Input for adding a drawing shape to a worksheet
1389#[derive(Deserialize, JsonSchema)]
1390#[serde(deny_unknown_fields)]
1391pub struct AddShapeInput {
1392    pub workbook_id: String,
1393    pub sheet_name: String,
1394    /// Anchor cell (e.g. "B2")
1395    pub cell: String,
1396    /// Shape type: rectangle, rounded_rectangle, ellipse, triangle, diamond, arrow, callout, text_box
1397    pub shape_type: ShapeKind,
1398    /// Width in pixels
1399    pub width: u32,
1400    /// Height in pixels
1401    pub height: u32,
1402    /// Optional text body for the shape
1403    #[serde(default)]
1404    pub text: Option<String>,
1405    /// Fill color as hex (e.g. "#FF0000")
1406    #[serde(default)]
1407    pub fill_color: Option<String>,
1408    /// Outline color as hex (e.g. "#000000")
1409    #[serde(default)]
1410    pub outline_color: Option<String>,
1411    /// Outline width in points
1412    #[serde(default)]
1413    pub outline_width: Option<f64>,
1414    /// Font size for the text body
1415    #[serde(default)]
1416    pub font_size: Option<f64>,
1417    /// Whether the text should be bold
1418    #[serde(default)]
1419    pub bold: Option<bool>,
1420}
1421
1422/// Input for setting document properties (core + app)
1423#[derive(Deserialize, JsonSchema)]
1424#[serde(deny_unknown_fields)]
1425pub struct SetDocPropertiesInput {
1426    pub workbook_id: String,
1427    #[serde(default)]
1428    pub title: Option<String>,
1429    #[serde(default)]
1430    pub author: Option<String>,
1431    #[serde(default)]
1432    pub subject: Option<String>,
1433    #[serde(default)]
1434    pub description: Option<String>,
1435    #[serde(default)]
1436    pub keywords: Option<String>,
1437    #[serde(default)]
1438    pub category: Option<String>,
1439    #[serde(default)]
1440    pub company: Option<String>,
1441}
1442
1443// ══════════════════════════════════════════════════════════════════
1444// v0.2.0: New tools — charts, pivots, controls, protection, save formats
1445// ══════════════════════════════════════════════════════════════════
1446
1447/// Input for adding a sunburst chart (Excel 2016+ ChartEx)
1448#[derive(Deserialize, JsonSchema)]
1449#[serde(deny_unknown_fields)]
1450pub struct AddSunburstChartInput {
1451    pub workbook_id: String,
1452    pub sheet_name: String,
1453    #[serde(default)]
1454    pub title: Option<String>,
1455    #[serde(default)]
1456    pub series_name: Option<String>,
1457    pub points: Vec<TreemapPoint>,
1458    #[serde(default = "default_chart_width")]
1459    pub width: u32,
1460    #[serde(default = "default_chart_height")]
1461    pub height: u32,
1462    #[serde(default)]
1463    pub cell: Option<String>,
1464}
1465
1466/// Input for adding a histogram chart (Excel 2016+ ChartEx)
1467#[derive(Deserialize, JsonSchema)]
1468#[serde(deny_unknown_fields)]
1469pub struct AddHistogramChartInput {
1470    pub workbook_id: String,
1471    pub sheet_name: String,
1472    #[serde(default)]
1473    pub title: Option<String>,
1474    #[serde(default)]
1475    pub series_name: Option<String>,
1476    pub points: Vec<FunnelPoint>,
1477    #[serde(default)]
1478    pub bin_count: Option<u32>,
1479    #[serde(default)]
1480    pub bin_width: Option<f64>,
1481    /// Show Pareto line overlay
1482    #[serde(default)]
1483    pub pareto: Option<bool>,
1484    #[serde(default = "default_chart_width")]
1485    pub width: u32,
1486    #[serde(default = "default_chart_height")]
1487    pub height: u32,
1488    #[serde(default)]
1489    pub cell: Option<String>,
1490}
1491
1492/// Input for adding a box & whisker chart (Excel 2016+ ChartEx)
1493#[derive(Deserialize, JsonSchema)]
1494#[serde(deny_unknown_fields)]
1495pub struct AddBoxWhiskerChartInput {
1496    pub workbook_id: String,
1497    pub sheet_name: String,
1498    #[serde(default)]
1499    pub title: Option<String>,
1500    #[serde(default)]
1501    pub series_name: Option<String>,
1502    pub points: Vec<FunnelPoint>,
1503    /// Show outlier points
1504    #[serde(default)]
1505    pub show_outliers: Option<bool>,
1506    /// Show mean markers
1507    #[serde(default)]
1508    pub show_mean: Option<bool>,
1509    /// Show inner data points
1510    #[serde(default)]
1511    pub show_inner_points: Option<bool>,
1512    #[serde(default = "default_chart_width")]
1513    pub width: u32,
1514    #[serde(default = "default_chart_height")]
1515    pub height: u32,
1516    #[serde(default)]
1517    pub cell: Option<String>,
1518}
1519
1520/// Input for adding a map chart (Excel 2016+ ChartEx)
1521#[derive(Deserialize, JsonSchema)]
1522#[serde(deny_unknown_fields)]
1523pub struct AddMapChartInput {
1524    pub workbook_id: String,
1525    pub sheet_name: String,
1526    #[serde(default)]
1527    pub title: Option<String>,
1528    #[serde(default)]
1529    pub series_name: Option<String>,
1530    pub points: Vec<FunnelPoint>,
1531    /// Map level: "world", "continent", "country", "state"
1532    #[serde(default)]
1533    pub map_level: Option<String>,
1534    #[serde(default = "default_chart_width")]
1535    pub width: u32,
1536    #[serde(default = "default_chart_height")]
1537    pub height: u32,
1538    #[serde(default)]
1539    pub cell: Option<String>,
1540}
1541
1542/// Input for adding a slicer to a pivot table
1543#[derive(Deserialize, JsonSchema)]
1544#[serde(deny_unknown_fields)]
1545pub struct AddSlicerInput {
1546    pub workbook_id: String,
1547    pub sheet_name: String,
1548    /// Name of the pivot table to connect to
1549    pub pivot_table_name: String,
1550    /// Field name to filter on
1551    pub field_name: String,
1552    /// Anchor cell for the slicer
1553    #[serde(default)]
1554    pub cell: Option<String>,
1555    #[serde(default)]
1556    pub width: Option<u32>,
1557    #[serde(default)]
1558    pub height: Option<u32>,
1559}
1560
1561/// Input for adding a timeline to a pivot table
1562#[derive(Deserialize, JsonSchema)]
1563#[serde(deny_unknown_fields)]
1564pub struct AddTimelineInput {
1565    pub workbook_id: String,
1566    pub sheet_name: String,
1567    /// Name of the pivot table to connect to
1568    pub pivot_table_name: String,
1569    /// Date field name
1570    pub field_name: String,
1571    /// Anchor cell for the timeline
1572    #[serde(default)]
1573    pub cell: Option<String>,
1574    #[serde(default)]
1575    pub width: Option<u32>,
1576    #[serde(default)]
1577    pub height: Option<u32>,
1578}
1579
1580/// Input for adding a form control (button, checkbox, spinner, dropdown)
1581#[derive(Deserialize, JsonSchema)]
1582#[serde(deny_unknown_fields)]
1583pub struct AddFormControlInput {
1584    pub workbook_id: String,
1585    pub sheet_name: String,
1586    /// Anchor cell
1587    pub cell: String,
1588    /// Control type: "button", "checkbox", "spinner", "dropdown", "radio", "scroll_bar", "group_box", "label"
1589    pub control_type: String,
1590    /// Display text/label
1591    #[serde(default)]
1592    pub text: Option<String>,
1593    /// Cell link for the control value
1594    #[serde(default)]
1595    pub cell_link: Option<String>,
1596    /// Input range (for dropdown/list controls)
1597    #[serde(default)]
1598    pub input_range: Option<String>,
1599    #[serde(default)]
1600    pub width: Option<u32>,
1601    #[serde(default)]
1602    pub height: Option<u32>,
1603}
1604
1605/// Input for saving in different formats
1606#[derive(Deserialize, JsonSchema)]
1607#[serde(deny_unknown_fields)]
1608pub struct SaveWorkbookAdvancedInput {
1609    pub workbook_id: String,
1610    pub file_path: String,
1611    /// Save format: "xlsx" (default), "xlsm", "template", "template_macro", "encrypted", "parallel"
1612    #[serde(default = "default_xlsx")]
1613    pub format: String,
1614    /// Password for encrypted save
1615    #[serde(default)]
1616    pub password: Option<String>,
1617}
1618
1619fn default_xlsx() -> String {
1620    "xlsx".to_string()
1621}
1622
1623/// Input for opening a password-protected workbook
1624#[derive(Deserialize, JsonSchema)]
1625#[serde(deny_unknown_fields)]
1626pub struct OpenWorkbookEncryptedInput {
1627    pub file_path: String,
1628    pub password: String,
1629}
1630
1631/// Input for managing named ranges with full CRUD and scoping
1632#[derive(Deserialize, JsonSchema)]
1633#[serde(deny_unknown_fields)]
1634pub struct ManageNamedRangesInput {
1635    pub workbook_id: String,
1636    /// "add", "update", "remove", "list", "add_scoped"
1637    pub action: String,
1638    #[serde(default)]
1639    pub name: Option<String>,
1640    #[serde(default)]
1641    pub formula: Option<String>,
1642    /// Sheet index for scoped names
1643    #[serde(default)]
1644    pub sheet_index: Option<usize>,
1645}
1646
1647/// Input for reading worksheet metadata (used_range, hyperlinks, merge_ranges, charts)
1648#[derive(Deserialize, JsonSchema)]
1649#[serde(deny_unknown_fields)]
1650pub struct ReadSheetMetadataInput {
1651    pub workbook_id: String,
1652    pub sheet_name: String,
1653    /// What to read: "used_range", "hyperlinks", "merge_ranges", "charts", "all"
1654    #[serde(default = "default_all")]
1655    pub info: String,
1656}
1657
1658fn default_all() -> String {
1659    "all".to_string()
1660}
1661
1662/// Input for adding a chart sheet (dedicated chart-only sheet)
1663#[derive(Deserialize, JsonSchema)]
1664#[serde(deny_unknown_fields)]
1665pub struct AddChartSheetInput {
1666    pub workbook_id: String,
1667    pub sheet_name: String,
1668    pub chart_type: ChartType,
1669    #[serde(default)]
1670    pub series: Vec<ChartSeriesInput>,
1671    #[serde(default)]
1672    pub data_range: Option<String>,
1673    #[serde(default)]
1674    pub title: Option<String>,
1675    #[serde(default)]
1676    pub x_axis_label: Option<String>,
1677    #[serde(default)]
1678    pub y_axis_label: Option<String>,
1679    #[serde(default)]
1680    pub legend_position: Option<LegendPosition>,
1681}
1682
1683/// Chart enhancement options (extend existing add_chart)
1684#[derive(Deserialize, JsonSchema)]
1685pub struct ChartEnhancements {
1686    /// Show data table below chart
1687    #[serde(default)]
1688    pub show_data_table: Option<bool>,
1689    /// 3D perspective rotation
1690    #[serde(default)]
1691    pub view_3d: Option<View3DInput>,
1692    /// Preset chart style number (1-48)
1693    #[serde(default)]
1694    pub style: Option<u8>,
1695    /// Accessibility alt text (title, description)
1696    #[serde(default)]
1697    pub alt_text: Option<AltTextInput>,
1698    /// Y-axis minimum value
1699    #[serde(default)]
1700    pub y_axis_min: Option<f64>,
1701    /// Y-axis maximum value
1702    #[serde(default)]
1703    pub y_axis_max: Option<f64>,
1704    /// Y-axis logarithmic base (e.g. 10)
1705    #[serde(default)]
1706    pub y_axis_log_base: Option<f64>,
1707    /// Reverse X axis
1708    #[serde(default)]
1709    pub x_axis_reverse: Option<bool>,
1710    /// Reverse Y axis
1711    #[serde(default)]
1712    pub y_axis_reverse: Option<bool>,
1713    /// X-axis number format
1714    #[serde(default)]
1715    pub x_axis_format: Option<String>,
1716    /// Y-axis number format
1717    #[serde(default)]
1718    pub y_axis_format: Option<String>,
1719    /// Show drop lines
1720    #[serde(default)]
1721    pub drop_lines: Option<bool>,
1722    /// Show high-low lines
1723    #[serde(default)]
1724    pub high_low_lines: Option<bool>,
1725    /// Plot area background fill color (hex)
1726    #[serde(default)]
1727    pub plot_area_fill: Option<String>,
1728}
1729
1730#[derive(Deserialize, JsonSchema)]
1731pub struct View3DInput {
1732    #[serde(default)]
1733    pub rot_x: Option<i16>,
1734    #[serde(default)]
1735    pub rot_y: Option<i16>,
1736    #[serde(default)]
1737    pub perspective: Option<u8>,
1738}
1739
1740#[derive(Deserialize, JsonSchema)]
1741pub struct AltTextInput {
1742    pub title: String,
1743    pub description: String,
1744}
1745
1746/// Enhanced chart series with additional options
1747#[derive(Deserialize, JsonSchema)]
1748pub struct ChartSeriesEnhanced {
1749    pub values: String,
1750    #[serde(default)]
1751    pub categories: Option<String>,
1752    #[serde(default)]
1753    pub name: Option<String>,
1754    #[serde(default)]
1755    pub color: Option<String>,
1756    #[serde(default)]
1757    pub data_labels: Option<bool>,
1758    #[serde(default)]
1759    pub trendline: Option<String>,
1760    #[serde(default)]
1761    pub marker: Option<String>,
1762    #[serde(default)]
1763    pub secondary_axis: Option<bool>,
1764    /// Line width in points
1765    #[serde(default)]
1766    pub line_width: Option<f64>,
1767    /// Dash style: "solid", "dash", "dot", "dash_dot"
1768    #[serde(default)]
1769    pub dash_style: Option<String>,
1770    /// Gradient stops: array of [color_hex, position_0_to_1]
1771    #[serde(default)]
1772    pub gradient: Option<Vec<GradientStopInput>>,
1773    /// Bubble sizes range (for bubble charts)
1774    #[serde(default)]
1775    pub bubble_sizes: Option<String>,
1776}
1777
1778#[derive(Deserialize, JsonSchema)]
1779pub struct GradientStopInput {
1780    pub color: String,
1781    pub position: f64,
1782}
1783
1784/// Sheet protection with granular options
1785#[derive(Deserialize, JsonSchema)]
1786pub struct SheetProtectionOptionsInput {
1787    #[serde(default)]
1788    pub password: Option<String>,
1789    #[serde(default)]
1790    pub insert_rows: Option<bool>,
1791    #[serde(default)]
1792    pub delete_rows: Option<bool>,
1793    #[serde(default)]
1794    pub insert_columns: Option<bool>,
1795    #[serde(default)]
1796    pub delete_columns: Option<bool>,
1797    #[serde(default)]
1798    pub format_cells: Option<bool>,
1799    #[serde(default)]
1800    pub format_columns: Option<bool>,
1801    #[serde(default)]
1802    pub format_rows: Option<bool>,
1803    #[serde(default)]
1804    pub sort: Option<bool>,
1805    #[serde(default)]
1806    pub insert_hyperlinks: Option<bool>,
1807    #[serde(default)]
1808    pub select_locked_cells: Option<bool>,
1809    #[serde(default)]
1810    pub select_unlocked_cells: Option<bool>,
1811    #[serde(default)]
1812    pub pivot_tables: Option<bool>,
1813}