1use super::{TableColumnDefinition, TableColumnId, TableRow, TableRowValue};
2use crate::data_sources::SelectedDataSource;
3use crate::formatting::Formatting;
4use crate::front_matter_schemas::{FrontMatterSchemaEntry, FrontMatterValueSchema};
5use crate::notebooks::{
6 front_matter::{FrontMatter, FrontMatterValue},
7 Cell, Label,
8};
9use crate::timestamps::TimeRange;
10#[cfg(feature = "fp-bindgen")]
11use fp_bindgen::prelude::*;
12use serde::{Deserialize, Serialize};
13use serde_json::Value;
14use typed_builder::TypedBuilder;
15
16#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
24#[cfg_attr(
25 feature = "fp-bindgen",
26 derive(Serializable),
27 fp(rust_module = "fiberplane_models::notebooks::operations")
28)]
29#[non_exhaustive]
30#[serde(tag = "type", rename_all = "snake_case")]
31#[allow(clippy::large_enum_variant)]
32pub enum Operation {
33 MoveCells(MoveCellsOperation),
35 ReplaceCells(ReplaceCellsOperation),
36
37 ReplaceText(ReplaceTextOperation),
39
40 UpdateNotebookTimeRange(UpdateNotebookTimeRangeOperation),
42
43 UpdateNotebookTitle(UpdateNotebookTitleOperation),
45
46 SetSelectedDataSource(SetSelectedDataSourceOperation),
48
49 AddLabel(AddLabelOperation),
51 ReplaceLabel(ReplaceLabelOperation),
52 RemoveLabel(RemoveLabelOperation),
53
54 ClearFrontMatter(ClearFrontMatterOperation),
56 InsertFrontMatterSchema(InsertFrontMatterSchemaOperation),
57 UpdateFrontMatterSchema(UpdateFrontMatterSchemaOperation),
58 MoveFrontMatterSchema(MoveFrontMatterSchemaOperation),
59 RemoveFrontMatterSchema(RemoveFrontMatterSchemaOperation),
60 UpdateFrontMatter(UpdateFrontMatterOperation),
63
64 InsertTableColumn(InsertTableColumnOperation),
67 RemoveTableColumn(RemoveTableColumnOperation),
68 UpdateTableColumnDefinition(UpdateTableColumnDefinitionOperation),
69 InsertTableRow(InsertTableRowOperation),
70 RemoveTableRow(RemoveTableRowOperation),
71}
72
73#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
75#[cfg_attr(
76 feature = "fp-bindgen",
77 derive(Serializable),
78 fp(rust_module = "fiberplane_models::notebooks::operations")
79)]
80#[non_exhaustive]
81#[serde(rename_all = "camelCase")]
82pub struct MoveCellsOperation {
83 pub cell_ids: Vec<String>,
87
88 pub from_index: u32,
90
91 pub to_index: u32,
93}
94
95#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize, TypedBuilder)]
106#[cfg_attr(
107 feature = "fp-bindgen",
108 derive(Serializable),
109 fp(rust_module = "fiberplane_models::notebooks::operations")
110)]
111#[non_exhaustive]
112#[serde(rename_all = "camelCase")]
113pub struct ReplaceCellsOperation {
114 #[builder(default)]
124 #[serde(default, skip_serializing_if = "Vec::is_empty")]
125 pub new_cells: Vec<CellWithIndex>,
126
127 #[builder(default)]
137 #[serde(default, skip_serializing_if = "Vec::is_empty")]
138 pub old_cells: Vec<CellWithIndex>,
139
140 #[builder(default, setter(strip_option))]
149 #[serde(default, skip_serializing_if = "Option::is_none")]
150 pub split_offset: Option<u32>,
151
152 #[builder(default, setter(strip_option))]
161 #[serde(default, skip_serializing_if = "Option::is_none")]
162 pub merge_offset: Option<u32>,
163
164 #[builder(default)]
175 #[serde(default, skip_serializing_if = "Vec::is_empty")]
176 pub new_referencing_cells: Vec<CellWithIndex>,
177
178 #[builder(default)]
189 #[serde(default, skip_serializing_if = "Vec::is_empty")]
190 pub old_referencing_cells: Vec<CellWithIndex>,
191}
192
193impl ReplaceCellsOperation {
194 pub fn all_new_cells(&self) -> impl Iterator<Item = &CellWithIndex> {
201 self.old_cells
202 .iter()
203 .chain(self.old_referencing_cells.iter())
204 }
205
206 pub fn all_newly_inserted_cells(&self) -> impl Iterator<Item = &CellWithIndex> {
209 self.newly_inserted_cells()
210 .chain(self.newly_inserted_referencing_cells())
211 }
212
213 pub fn all_old_cells(&self) -> impl Iterator<Item = &CellWithIndex> {
220 self.old_cells
221 .iter()
222 .chain(self.old_referencing_cells.iter())
223 }
224
225 pub fn all_old_removed_cells(&self) -> impl Iterator<Item = &CellWithIndex> {
228 self.old_removed_cells()
229 .chain(self.old_removed_referencing_cells())
230 }
231
232 pub fn newly_inserted_cells(&self) -> impl Iterator<Item = &CellWithIndex> {
234 self.new_cells.iter().filter(move |new_cell| {
235 !self
236 .old_cells
237 .iter()
238 .any(|old_cell| old_cell.id() == new_cell.id())
239 })
240 }
241
242 pub fn newly_inserted_referencing_cells(&self) -> impl Iterator<Item = &CellWithIndex> {
244 self.new_referencing_cells.iter().filter(move |new_cell| {
245 !self
246 .old_referencing_cells
247 .iter()
248 .any(|old_cell| old_cell.id() == new_cell.id())
249 })
250 }
251
252 pub fn old_removed_cells(&self) -> impl Iterator<Item = &CellWithIndex> {
254 self.old_cells.iter().filter(move |old_cell| {
255 !self
256 .new_cells
257 .iter()
258 .any(|new_cell| new_cell.id() == old_cell.id())
259 })
260 }
261
262 pub fn old_removed_referencing_cells(&self) -> impl Iterator<Item = &CellWithIndex> {
264 self.old_referencing_cells.iter().filter(move |old_cell| {
265 !self
266 .new_referencing_cells
267 .iter()
268 .any(|new_cell| new_cell.id() == old_cell.id())
269 })
270 }
271}
272
273#[derive(Clone, Debug, Default, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
275#[cfg_attr(
276 feature = "fp-bindgen",
277 derive(Serializable),
278 fp(rust_module = "fiberplane_models::notebooks::operations")
279)]
280#[non_exhaustive]
281#[serde(rename_all = "camelCase")]
282pub struct ReplaceTextOperation {
283 #[builder(setter(into))]
285 pub cell_id: String,
286
287 #[builder(default, setter(into, strip_option))]
289 #[serde(default, skip_serializing_if = "Option::is_none")]
290 pub field: Option<String>,
291
292 pub offset: u32,
297
298 #[builder(default, setter(into))]
300 pub new_text: String,
301
302 #[builder(default, setter(strip_option))]
306 #[serde(default, skip_serializing_if = "Option::is_none")]
307 pub new_formatting: Option<Formatting>,
308
309 #[builder(default, setter(into))]
311 pub old_text: String,
312
313 #[builder(default, setter(strip_option))]
320 #[serde(default, skip_serializing_if = "Option::is_none")]
321 pub old_formatting: Option<Formatting>,
322}
323
324#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
326#[cfg_attr(
327 feature = "fp-bindgen",
328 derive(Serializable),
329 fp(rust_module = "fiberplane_models::notebooks::operations")
330)]
331#[non_exhaustive]
332#[serde(rename_all = "camelCase")]
333pub struct UpdateNotebookTimeRangeOperation {
334 pub old_time_range: TimeRange,
335 pub time_range: TimeRange,
336}
337
338#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
340#[cfg_attr(
341 feature = "fp-bindgen",
342 derive(Serializable),
343 fp(rust_module = "fiberplane_models::notebooks::operations")
344)]
345#[non_exhaustive]
346#[serde(rename_all = "camelCase")]
347pub struct UpdateNotebookTitleOperation {
348 #[builder(default, setter(into))]
349 pub old_title: String,
350
351 #[builder(default, setter(into))]
352 pub title: String,
353}
354
355#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
356#[cfg_attr(
357 feature = "fp-bindgen",
358 derive(Serializable),
359 fp(rust_module = "fiberplane_models::notebooks::operations")
360)]
361#[non_exhaustive]
362#[serde(rename_all = "camelCase")]
363pub struct SetSelectedDataSourceOperation {
364 #[builder(setter(into))]
365 pub provider_type: String,
366
367 #[builder(default)]
368 #[serde(default, skip_serializing_if = "Option::is_none")]
369 pub old_selected_data_source: Option<SelectedDataSource>,
370
371 #[builder(default)]
372 #[serde(default, skip_serializing_if = "Option::is_none")]
373 pub new_selected_data_source: Option<SelectedDataSource>,
374}
375
376#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TypedBuilder)]
377#[cfg_attr(
378 feature = "fp-bindgen",
379 derive(Serializable),
380 fp(rust_module = "fiberplane_models::notebooks::operations")
381)]
382#[non_exhaustive]
383#[serde(rename_all = "camelCase")]
384pub struct CellWithIndex {
385 pub cell: Cell,
386 pub index: u32,
387}
388
389impl CellWithIndex {
390 pub fn new(cell: Cell, index: u32) -> CellWithIndex {
391 CellWithIndex { cell, index }
392 }
393
394 pub fn formatting(&self) -> Option<&Formatting> {
395 self.cell.formatting()
396 }
397
398 pub fn id(&self) -> &str {
399 self.cell.id()
400 }
401
402 pub fn text(&self) -> Option<&str> {
403 self.cell.text()
404 }
405}
406
407#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
409#[cfg_attr(
410 feature = "fp-bindgen",
411 derive(Serializable),
412 fp(rust_module = "fiberplane_models::notebooks::operations")
413)]
414#[non_exhaustive]
415#[serde(rename_all = "camelCase")]
416pub struct AddLabelOperation {
417 pub label: Label,
419}
420
421#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
423#[cfg_attr(
424 feature = "fp-bindgen",
425 derive(Serializable),
426 fp(rust_module = "fiberplane_models::notebooks::operations")
427)]
428#[non_exhaustive]
429#[serde(rename_all = "camelCase")]
430pub struct ReplaceLabelOperation {
431 pub old_label: Label,
433
434 pub new_label: Label,
436}
437
438#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
440#[cfg_attr(
441 feature = "fp-bindgen",
442 derive(Serializable),
443 fp(rust_module = "fiberplane_models::notebooks::operations")
444)]
445#[non_exhaustive]
446#[serde(rename_all = "camelCase")]
447pub struct RemoveLabelOperation {
448 pub label: Label,
449}
450
451#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
453#[cfg_attr(
454 feature = "fp-bindgen",
455 derive(Serializable),
456 fp(rust_module = "fiberplane_models::notebooks::operations")
457)]
458#[non_exhaustive]
459#[serde(rename_all = "camelCase")]
460pub struct UpdateFrontMatterOperation {
461 pub old_front_matter: FrontMatter,
462 pub new_front_matter: FrontMatter,
463}
464
465#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
467#[cfg_attr(
468 feature = "fp-bindgen",
469 derive(Serializable),
470 fp(rust_module = "fiberplane_models::notebooks::operations")
471)]
472#[non_exhaustive]
473#[serde(rename_all = "camelCase")]
474pub struct ClearFrontMatterOperation {
475 pub front_matter: FrontMatter,
476}
477
478#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TypedBuilder)]
480#[cfg_attr(
481 feature = "fp-bindgen",
482 derive(Serializable),
483 fp(rust_module = "fiberplane_models::notebooks::operations")
484)]
485#[non_exhaustive]
486#[serde(rename_all = "camelCase")]
487pub struct InsertFrontMatterSchemaOperation {
488 #[builder(default, setter(into))]
493 #[serde(default, skip_serializing_if = "Option::is_none")]
494 pub key_of_entry_before_insertion_location: Option<String>,
495
496 #[builder(default, setter(into))]
499 #[serde(default, skip_serializing_if = "Option::is_none")]
500 pub key_of_entry_after_insertion_location: Option<String>,
501
502 pub to_index: u32,
504
505 pub insertions: Vec<FrontMatterSchemaRow>,
507}
508
509#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
510#[cfg_attr(
511 feature = "fp-bindgen",
512 derive(Serializable),
513 fp(rust_module = "fiberplane_models::notebooks::operations")
514)]
515#[serde(rename_all = "camelCase")]
516#[non_exhaustive]
517pub struct FrontMatterSchemaRow {
518 #[builder(setter(into))]
519 pub key: String,
520
521 #[builder(setter(into))]
522 pub schema: FrontMatterValueSchema,
523
524 #[serde(default, skip_serializing_if = "Option::is_none")]
525 #[builder(default, setter(into))]
526 pub value: Option<FrontMatterValue>,
527}
528
529impl From<(FrontMatterSchemaEntry, Option<Value>)> for FrontMatterSchemaRow {
530 fn from((schema, value): (FrontMatterSchemaEntry, Option<Value>)) -> Self {
531 Self {
532 key: schema.key,
533 schema: schema.schema,
534 value: value.map(Into::into),
535 }
536 }
537}
538
539#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, TypedBuilder)]
542#[cfg_attr(
543 feature = "fp-bindgen",
544 derive(Serializable),
545 fp(rust_module = "fiberplane_models::notebooks::operations")
546)]
547#[non_exhaustive]
548#[serde(rename_all = "camelCase")]
549pub struct UpdateFrontMatterSchemaOperation {
550 #[builder(setter(into))]
552 pub key: String,
553
554 #[builder(setter(into))]
557 pub old_schema: FrontMatterValueSchema,
558
559 #[builder(default)]
564 #[serde(default, skip_serializing_if = "Option::is_none")]
565 pub old_value: Option<FrontMatterValue>,
566
567 #[builder(setter(into))]
575 #[serde(default, skip_serializing_if = "Option::is_none")]
576 pub new_schema: Option<FrontMatterValueSchema>,
577
578 #[builder(default)]
588 #[serde(default, skip_serializing_if = "Option::is_none")]
589 pub new_value: Option<FrontMatterValue>,
590
591 #[builder(setter(strip_bool))]
594 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
595 pub delete_value: bool,
596}
597
598#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
600#[cfg_attr(
601 feature = "fp-bindgen",
602 derive(Serializable),
603 fp(rust_module = "fiberplane_models::notebooks::operations")
604)]
605#[non_exhaustive]
606#[serde(rename_all = "camelCase")]
607pub struct MoveFrontMatterSchemaOperation {
608 pub keys: Vec<String>,
612
613 pub from_index: u32,
615
616 pub to_index: u32,
618}
619
620#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
622#[cfg_attr(
623 feature = "fp-bindgen",
624 derive(Serializable),
625 fp(rust_module = "fiberplane_models::notebooks::operations")
626)]
627#[non_exhaustive]
628#[serde(rename_all = "camelCase")]
629pub struct RemoveFrontMatterSchemaOperation {
630 #[builder(default, setter(into))]
633 #[serde(default, skip_serializing_if = "Option::is_none")]
634 pub key_of_entry_before_deletion_range: Option<String>,
635
636 #[builder(default, setter(into))]
639 #[serde(default, skip_serializing_if = "Option::is_none")]
640 pub key_of_entry_after_deletion_range: Option<String>,
641
642 pub from_index: u32,
645
646 pub deletions: Vec<FrontMatterSchemaRow>,
648}
649
650#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
651#[cfg_attr(
652 feature = "fp-bindgen",
653 derive(Serializable),
654 fp(rust_module = "fiberplane_models::notebooks::operations")
655)]
656#[non_exhaustive]
657#[serde(rename_all = "camelCase")]
658pub struct CellAppendText {
659 #[builder(setter(into))]
660 pub content: String,
661
662 #[builder(default)]
663 #[serde(default)]
664 pub formatting: Formatting,
665}
666
667#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
668#[cfg_attr(
669 feature = "fp-bindgen",
670 derive(Serializable),
671 fp(rust_module = "fiberplane_models::notebooks::operations")
672)]
673#[non_exhaustive]
674#[serde(rename_all = "camelCase")]
675pub struct CellReplaceText {
676 pub offset: u32,
681
682 #[builder(default, setter(into))]
684 pub new_text: String,
685
686 #[builder(default, setter(strip_option))]
690 #[serde(default, skip_serializing_if = "Option::is_none")]
691 pub new_formatting: Option<Formatting>,
692
693 #[builder(default, setter(into))]
695 pub old_text: String,
696
697 #[builder(default, setter(strip_option))]
704 #[serde(default, skip_serializing_if = "Option::is_none")]
705 pub old_formatting: Option<Formatting>,
706}
707
708#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
709#[cfg_attr(
710 feature = "fp-bindgen",
711 derive(Serializable),
712 fp(rust_module = "fiberplane_models::notebooks::operations")
713)]
714#[non_exhaustive]
715#[serde(rename_all = "camelCase")]
716pub struct InsertTableColumnOperation {
717 #[builder(setter(into))]
719 pub cell_id: String,
720
721 pub column_def: TableColumnDefinition,
723
724 pub index: u32,
726
727 #[builder(setter(into))]
731 pub values: Vec<TableRowValue>,
732}
733
734#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
735#[cfg_attr(
736 feature = "fp-bindgen",
737 derive(Serializable),
738 fp(rust_module = "fiberplane_models::notebooks::operations")
739)]
740#[non_exhaustive]
741#[serde(rename_all = "camelCase")]
742pub struct RemoveTableColumnOperation {
743 #[builder(setter(into))]
745 pub cell_id: String,
746
747 pub column_def: TableColumnDefinition,
749
750 pub index: u32,
752
753 #[builder(setter(into))]
757 pub values: Vec<TableRowValue>,
758}
759
760#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
761#[cfg_attr(
762 feature = "fp-bindgen",
763 derive(Serializable),
764 fp(rust_module = "fiberplane_models::notebooks::operations")
765)]
766#[non_exhaustive]
767#[serde(rename_all = "camelCase")]
768pub struct UpdateTableColumnDefinitionOperation {
769 #[builder(setter(into))]
771 pub cell_id: String,
772
773 pub column_id: TableColumnId,
775
776 #[builder(setter(into))]
778 pub new_title: String,
779
780 #[builder(setter(into))]
782 pub old_title: String,
783}
784
785#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
786#[cfg_attr(
787 feature = "fp-bindgen",
788 derive(Serializable),
789 fp(rust_module = "fiberplane_models::notebooks::operations")
790)]
791#[non_exhaustive]
792#[serde(rename_all = "camelCase")]
793pub struct InsertTableRowOperation {
794 #[builder(setter(into))]
796 pub cell_id: String,
797
798 pub row: TableRow,
800
801 pub index: u32,
803}
804
805#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, TypedBuilder)]
806#[cfg_attr(
807 feature = "fp-bindgen",
808 derive(Serializable),
809 fp(rust_module = "fiberplane_models::notebooks::operations")
810)]
811#[non_exhaustive]
812#[serde(rename_all = "camelCase")]
813pub struct RemoveTableRowOperation {
814 #[builder(setter(into))]
816 pub cell_id: String,
817
818 pub row: TableRow,
820
821 pub index: u32,
823}