logisheets_controller/edit_action/
mod.rs

1use logisheets_base::{async_func::Task, CellId, SheetId};
2use serde::{Deserialize, Serialize};
3
4pub trait Payload: Into<EditPayload> {}
5
6/// `EditAction` represents your update behavior to the workbook.
7#[derive(Debug)]
8#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
9#[cfg_attr(
10    feature = "gents",
11    ts(file_name = "edit_action.ts", rename_all = "camelCase")
12)]
13pub enum EditAction {
14    Undo,
15    Redo,
16    Payloads(PayloadsAction),
17    Recalc(Vec<RecalcCell>),
18}
19
20#[derive(Debug)]
21#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
22#[cfg_attr(
23    feature = "gents",
24    ts(file_name = "recalc_cell.ts", rename_all = "camelCase")
25)]
26pub struct RecalcCell {
27    pub sheet_id: SheetId,
28    pub cell_id: CellId,
29}
30
31impl EditAction {
32    pub fn undo() -> Self {
33        Self::Undo
34    }
35
36    pub fn redo() -> Self {
37        Self::Redo
38    }
39}
40
41impl From<PayloadsAction> for EditAction {
42    fn from(value: PayloadsAction) -> Self {
43        EditAction::Payloads(value)
44    }
45}
46
47/// A `PayloadsAction` contains one or more `EditPayload`.
48/// These `EditPayload`s will be withdrawn at the same time if user undo it.
49/// And if one of the payload is failed to be executed, this `EditAction` will
50/// not do anything at all.
51///
52/// An `EditPayload` represents an atomic update of a workbook and they will be
53/// executed in sequence. That means it is a totally different result between
54/// updating a cell at B4 before inserting and after inserting.
55#[derive(Debug, Clone)]
56#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
57#[cfg_attr(
58    feature = "gents",
59    ts(file_name = "payloads_action.ts", rename_all = "camelCase")
60)]
61pub struct PayloadsAction {
62    pub payloads: Vec<EditPayload>,
63    pub undoable: bool,
64}
65
66impl PayloadsAction {
67    pub fn new(undoable: bool) -> Self {
68        PayloadsAction {
69            payloads: vec![],
70            undoable,
71        }
72    }
73
74    pub fn add_payload<P: Payload>(mut self, payload: P) -> Self {
75        self.payloads.push(payload.into());
76        self
77    }
78}
79
80/// `EditPayload` is the basic update unit of the Workbook. Developers can config their own
81/// `EditAction` (e.g. setting a button to create a table) to facilitate their users.
82#[derive(Debug, Clone)]
83#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
84#[cfg_attr(
85    feature = "gents",
86    ts(file_name = "edit_payload.ts", rename_all = "camelCase")
87)]
88pub enum EditPayload {
89    // Block
90    BlockInput(BlockInput),
91    MoveBlock(MoveBlock),
92    RemoveBlock(RemoveBlock),
93    CreateBlock(CreateBlock),
94
95    // Style
96    StyleUpdate(StyleUpdate),
97    BlockStyleUpdate(BlockStyleUpdate),
98
99    CellInput(CellInput),
100    CellClear(CellClear),
101    SetColWidth(SetColWidth),
102    SetRowHeight(SetRowHeight),
103    SetVisible(SetVisible),
104    // Sheet
105    SheetRename(SheetRename),
106    CreateSheet(CreateSheet),
107    DeleteSheet(DeleteSheet),
108    // Shifting
109    InsertCols(InsertCols),
110    DeleteCols(DeleteCols),
111    InsertRows(InsertRows),
112    DeleteRows(DeleteRows),
113    InsertColsInBlock(InsertColsInBlock),
114    DeleteColsInBlock(DeleteColsInBlock),
115    InsertRowsInBlock(InsertRowsInBlock),
116    DeleteRowsInBlock(DeleteRowsInBlock),
117}
118
119#[derive(Debug, Clone)]
120#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
121#[cfg_attr(
122    feature = "gents",
123    ts(file_name = "create_sheet.ts", rename_all = "camelCase")
124)]
125pub struct CreateSheet {
126    pub idx: usize,
127    pub new_name: String,
128}
129
130#[derive(Debug, Clone)]
131#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
132#[cfg_attr(
133    feature = "gents",
134    ts(file_name = "delete_sheet.ts", rename_all = "camelCase")
135)]
136pub struct DeleteSheet {
137    pub idx: usize,
138}
139
140/// Find a sheet by its name and rename it. If no sheet is found, do nothing.
141#[derive(Debug, Clone)]
142#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
143#[cfg_attr(
144    feature = "gents",
145    ts(file_name = "sheet_rename.ts", rename_all = "camelCase")
146)]
147pub struct SheetRename {
148    pub old_name: Option<String>,
149    pub idx: Option<usize>,
150    pub new_name: String,
151}
152
153#[derive(Debug, Clone)]
154#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
155#[cfg_attr(
156    feature = "gents",
157    ts(file_name = "delete_rows.ts", rename_all = "camelCase")
158)]
159pub struct DeleteRows {
160    pub sheet_idx: usize,
161    pub start: usize,
162    pub count: usize,
163}
164
165#[derive(Debug, Clone)]
166#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
167#[cfg_attr(
168    feature = "gents",
169    ts(file_name = "insert_rows.ts", rename_all = "camelCase")
170)]
171pub struct InsertRows {
172    pub sheet_idx: usize,
173    pub start: usize,
174    pub count: usize,
175}
176
177#[derive(Debug, Clone)]
178#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
179#[cfg_attr(
180    feature = "gents",
181    ts(file_name = "delete_cols.ts", rename_all = "camelCase")
182)]
183pub struct DeleteCols {
184    pub sheet_idx: usize,
185    pub start: usize,
186    pub count: usize,
187}
188
189#[derive(Debug, Clone)]
190#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
191#[cfg_attr(
192    feature = "gents",
193    ts(file_name = "insert_cols.ts", rename_all = "camelCase")
194)]
195pub struct InsertCols {
196    pub sheet_idx: usize,
197    pub start: usize,
198    pub count: usize,
199}
200
201/// Take the `content` as input to the cell. The type of the `content` can be referred automatically.
202#[derive(Debug, Clone)]
203#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
204#[cfg_attr(
205    feature = "gents",
206    ts(file_name = "cell_input.ts", rename_all = "camelCase")
207)]
208pub struct CellInput {
209    pub sheet_idx: usize,
210    pub row: usize,
211    pub col: usize,
212    pub content: String,
213}
214
215#[derive(Debug, Clone)]
216#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
217#[cfg_attr(
218    feature = "gents",
219    ts(file_name = "cell_clear.ts", rename_all = "camelCase")
220)]
221pub struct CellClear {
222    pub sheet_idx: usize,
223    pub row: usize,
224    pub col: usize,
225}
226
227/// Create a new block.
228///
229/// Note that the block id is assigned by you. You are supposed to
230/// manage all your blocks. If the `block id` is already existed, engines
231/// will remove the old one.
232#[derive(Debug, Clone)]
233#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
234#[cfg_attr(
235    feature = "gents",
236    ts(file_name = "create_block.ts", rename_all = "camelCase")
237)]
238pub struct CreateBlock {
239    pub sheet_idx: usize,
240    pub id: usize,
241    pub master_row: usize,
242    pub master_col: usize,
243    pub row_cnt: usize,
244    pub col_cnt: usize,
245}
246
247#[derive(Debug, Clone)]
248#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
249#[cfg_attr(
250    feature = "gents",
251    ts(file_name = "set_row_height.ts", rename_all = "camelCase")
252)]
253pub struct SetRowHeight {
254    pub sheet_idx: usize,
255    pub row: usize,
256    pub height: f64,
257}
258
259#[derive(Debug, Clone)]
260#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
261#[cfg_attr(
262    feature = "gents",
263    ts(file_name = "set_col_width.ts", rename_all = "camelCase")
264)]
265pub struct SetColWidth {
266    pub sheet_idx: usize,
267    pub col: usize,
268    pub width: f64,
269}
270
271#[derive(Debug, Clone)]
272#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
273#[cfg_attr(
274    feature = "gents",
275    ts(file_name = "move_block.ts", rename_all = "camelCase")
276)]
277pub struct MoveBlock {
278    pub sheet_idx: usize,
279    pub id: usize,
280    pub new_master_row: usize,
281    pub new_master_col: usize,
282}
283
284#[derive(Debug, Clone)]
285#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
286#[cfg_attr(
287    feature = "gents",
288    ts(file_name = "remove_block.ts", rename_all = "camelCase")
289)]
290pub struct RemoveBlock {
291    pub sheet_idx: usize,
292    pub id: usize,
293}
294
295#[derive(Debug, Clone)]
296#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
297#[cfg_attr(
298    feature = "gents",
299    ts(file_name = "block_input.ts", rename_all = "camelCase")
300)]
301pub struct BlockInput {
302    pub sheet_idx: usize,
303    pub block_id: usize,
304    pub row: usize,
305    pub col: usize,
306    pub input: String,
307}
308
309impl From<BlockInput> for EditPayload {
310    fn from(value: BlockInput) -> Self {
311        EditPayload::BlockInput(value)
312    }
313}
314
315#[derive(Debug, Clone)]
316#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
317#[cfg_attr(
318    feature = "gents",
319    ts(file_name = "delete_rows_in_block.ts", rename_all = "camelCase")
320)]
321pub struct DeleteRowsInBlock {
322    pub sheet_idx: usize,
323    pub block_id: usize,
324    pub start: usize,
325    pub cnt: usize,
326}
327
328#[derive(Debug, Clone)]
329#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
330#[cfg_attr(
331    feature = "gents",
332    ts(file_name = "insert_rows_in_block.ts", rename_all = "camelCase")
333)]
334pub struct InsertRowsInBlock {
335    pub sheet_idx: usize,
336    pub block_id: usize,
337    pub start: usize,
338    pub cnt: usize,
339}
340
341#[derive(Debug, Clone)]
342#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
343#[cfg_attr(
344    feature = "gents",
345    ts(file_name = "insert_cols_in_block.ts", rename_all = "camelCase")
346)]
347pub struct InsertColsInBlock {
348    pub sheet_idx: usize,
349    pub block_id: usize,
350    pub start: usize,
351    pub cnt: usize,
352}
353
354#[derive(Debug, Clone)]
355#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
356#[cfg_attr(
357    feature = "gents",
358    ts(file_name = "delete_cols_in_block.ts", rename_all = "camelCase")
359)]
360pub struct DeleteColsInBlock {
361    pub sheet_idx: usize,
362    pub block_id: usize,
363    pub start: usize,
364    pub cnt: usize,
365}
366
367#[derive(Debug, Clone)]
368#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
369#[cfg_attr(
370    feature = "gents",
371    ts(file_name = "block_style_update.ts", rename_all = "camelCase")
372)]
373pub struct BlockStyleUpdate {
374    pub sheet_idx: usize,
375    pub block_id: usize,
376    pub row: usize,
377    pub col: usize,
378    pub style_update: StyleUpdateType,
379}
380
381#[derive(Default, Debug, Clone)]
382#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
383#[cfg_attr(
384    feature = "gents",
385    ts(file_name = "set_visible.ts", rename_all = "camelCase")
386)]
387pub struct SetVisible {
388    pub is_row: bool,
389    pub sheet_idx: usize,
390    pub start: usize,
391    pub visible: bool,
392}
393
394/// `ActionEffect` represents the result of handling `EditAction`.
395/// `version` would be increased if the action is successfully handled.
396///
397/// What's more, since `LogiSheets` provides developers with the ability
398/// of developing their own functions, in these cases, `engine` will not know
399/// how to compute them and just return it the JS side.
400#[derive(Default, Debug, Serialize)]
401#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
402#[cfg_attr(
403    feature = "gents",
404    ts(file_name = "action_effect.ts", rename_all = "camelCase")
405)]
406pub struct ActionEffect {
407    /// The latest version after processing an action. 0 means latest version
408    pub version: u32,
409    /// Tasks should be calculated outside this engine(mainly because of network limitations and customer defined)
410    pub async_tasks: Vec<Task>,
411    pub status: StatusCode,
412}
413
414impl ActionEffect {
415    pub fn from_err(e: u8) -> Self {
416        ActionEffect {
417            status: StatusCode::Err(e),
418            ..Default::default()
419        }
420    }
421
422    pub fn from(version: u32, tasks: Vec<Task>, ty: WorkbookUpdateType) -> Self {
423        ActionEffect {
424            version,
425            async_tasks: tasks,
426            status: StatusCode::Ok(ty),
427        }
428    }
429}
430
431/// The results of the tasks which are passed to JS side to calculate previously.
432#[derive(Default, Debug, Deserialize)]
433#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
434#[cfg_attr(
435    feature = "gents",
436    ts(file_name = "async_func_result.ts", rename_all = "camelCase")
437)]
438pub struct AsyncFuncResult {
439    pub tasks: Vec<Task>,
440    /// These strings can be numbers, strings and other things.
441    /// Note that now error types are hardcoded, which means if the
442    /// value is equal to the a specific string like `#TIMEOUT!`,
443    /// it is reagarded as an error.
444    pub values: Vec<String>,
445}
446
447#[derive(Debug, Serialize)]
448#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
449#[cfg_attr(
450    feature = "gents",
451    ts(file_name = "status_code.ts", rename_all = "camelCase")
452)]
453pub enum StatusCode {
454    Ok(WorkbookUpdateType), // when there is no other history version for undo/redo, return false.
455    Err(u8),
456}
457
458#[derive(Debug, Serialize)]
459#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
460#[cfg_attr(
461    feature = "gents",
462    ts(file_name = "workbook_update_type.ts", rename_all = "camelCase")
463)]
464pub enum WorkbookUpdateType {
465    DoNothing,
466    Cell,
467    Sheet,
468    SheetAndCell,
469    UndoNothing,
470    RedoNothing,
471    Undo,
472    Redo,
473}
474
475impl Default for StatusCode {
476    fn default() -> Self {
477        Self::Ok(WorkbookUpdateType::Cell)
478    }
479}
480
481use crate::controller::style::PatternFill;
482use logisheets_workbook::prelude::*;
483
484#[derive(Debug, Clone)]
485#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
486#[cfg_attr(
487    feature = "gents",
488    ts(file_name = "style_update.ts", rename_all = "camelCase")
489)]
490pub struct StyleUpdate {
491    pub sheet_idx: usize,
492    pub row: usize,
493    pub col: usize,
494    pub ty: StyleUpdateType,
495}
496
497pub type Color = String;
498
499#[derive(Debug, Clone)]
500#[cfg_attr(feature = "gents", derive(gents_derives::TS))]
501#[cfg_attr(
502    feature = "gents",
503    ts(file_name = "style_update_type.ts", rename_all = "camelCase")
504)]
505pub struct StyleUpdateType {
506    pub set_font_bold: Option<bool>,
507    pub set_font_italic: Option<bool>,
508    pub set_font_underline: Option<StUnderlineValues>,
509    pub set_font_color: Option<Color>,
510    pub set_font_size: Option<f64>,
511    pub set_font_name: Option<String>,
512    pub set_font_outline: Option<bool>,
513    pub set_font_shadow: Option<bool>,
514    pub set_font_strike: Option<bool>,
515    pub set_font_condense: Option<bool>,
516    pub set_left_border_color: Option<Color>,
517    pub set_right_border_color: Option<Color>,
518    pub set_top_border_color: Option<Color>,
519    pub set_bottom_border_color: Option<Color>,
520    pub set_left_border_style: Option<StBorderStyle>,
521    pub set_right_border_style: Option<StBorderStyle>,
522    pub set_top_border_style: Option<StBorderStyle>,
523    pub set_bottom_border_style: Option<StBorderStyle>,
524    pub set_border_giagonal_up: Option<bool>,
525    pub set_border_giagonal_down: Option<bool>,
526    pub set_border_outline: Option<bool>,
527    pub set_pattern_fill: Option<PatternFill>,
528}
529
530impl From<BlockStyleUpdate> for EditPayload {
531    fn from(value: BlockStyleUpdate) -> Self {
532        EditPayload::BlockStyleUpdate(value)
533    }
534}
535impl From<CellInput> for EditPayload {
536    fn from(value: CellInput) -> Self {
537        EditPayload::CellInput(value)
538    }
539}
540impl From<CreateBlock> for EditPayload {
541    fn from(value: CreateBlock) -> Self {
542        EditPayload::CreateBlock(value)
543    }
544}
545impl From<MoveBlock> for EditPayload {
546    fn from(value: MoveBlock) -> Self {
547        EditPayload::MoveBlock(value)
548    }
549}
550impl From<RemoveBlock> for EditPayload {
551    fn from(value: RemoveBlock) -> Self {
552        EditPayload::RemoveBlock(value)
553    }
554}
555impl From<SetColWidth> for EditPayload {
556    fn from(value: SetColWidth) -> Self {
557        EditPayload::SetColWidth(value)
558    }
559}
560impl From<SetRowHeight> for EditPayload {
561    fn from(value: SetRowHeight) -> Self {
562        EditPayload::SetRowHeight(value)
563    }
564}
565impl From<SetVisible> for EditPayload {
566    fn from(value: SetVisible) -> Self {
567        EditPayload::SetVisible(value)
568    }
569}
570impl From<SheetRename> for EditPayload {
571    fn from(value: SheetRename) -> Self {
572        EditPayload::SheetRename(value)
573    }
574}
575impl From<StyleUpdate> for EditPayload {
576    fn from(value: StyleUpdate) -> Self {
577        EditPayload::StyleUpdate(value)
578    }
579}
580impl From<InsertCols> for EditPayload {
581    fn from(value: InsertCols) -> Self {
582        EditPayload::InsertCols(value)
583    }
584}
585impl From<InsertRows> for EditPayload {
586    fn from(value: InsertRows) -> Self {
587        EditPayload::InsertRows(value)
588    }
589}
590impl From<DeleteRows> for EditPayload {
591    fn from(value: DeleteRows) -> Self {
592        EditPayload::DeleteRows(value)
593    }
594}
595impl From<DeleteCols> for EditPayload {
596    fn from(value: DeleteCols) -> Self {
597        EditPayload::DeleteCols(value)
598    }
599}
600
601impl From<InsertColsInBlock> for EditPayload {
602    fn from(value: InsertColsInBlock) -> Self {
603        EditPayload::InsertColsInBlock(value)
604    }
605}
606impl From<InsertRowsInBlock> for EditPayload {
607    fn from(value: InsertRowsInBlock) -> Self {
608        EditPayload::InsertRowsInBlock(value)
609    }
610}
611
612impl From<DeleteRowsInBlock> for EditPayload {
613    fn from(value: DeleteRowsInBlock) -> Self {
614        EditPayload::DeleteRowsInBlock(value)
615    }
616}
617
618impl From<DeleteColsInBlock> for EditPayload {
619    fn from(value: DeleteColsInBlock) -> Self {
620        EditPayload::DeleteColsInBlock(value)
621    }
622}
623
624impl From<CreateSheet> for EditPayload {
625    fn from(value: CreateSheet) -> Self {
626        EditPayload::CreateSheet(value)
627    }
628}
629
630impl From<DeleteSheet> for EditPayload {
631    fn from(value: DeleteSheet) -> Self {
632        EditPayload::DeleteSheet(value)
633    }
634}
635
636impl Payload for BlockInput {}
637impl Payload for BlockStyleUpdate {}
638impl Payload for CellInput {}
639impl Payload for CreateBlock {}
640impl Payload for MoveBlock {}
641impl Payload for RemoveBlock {}
642impl Payload for SetColWidth {}
643impl Payload for SetRowHeight {}
644impl Payload for SetVisible {}
645impl Payload for SheetRename {}
646impl Payload for CreateSheet {}
647impl Payload for DeleteSheet {}
648impl Payload for StyleUpdate {}
649impl Payload for InsertCols {}
650impl Payload for InsertRows {}
651impl Payload for DeleteCols {}
652impl Payload for DeleteRows {}
653impl Payload for InsertColsInBlock {}
654impl Payload for InsertRowsInBlock {}
655impl Payload for DeleteColsInBlock {}
656impl Payload for DeleteRowsInBlock {}