From 47e56cc4a912c5bd7d1685f49b8ab2161f58daf0 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 26 Sep 2025 10:59:31 +0800 Subject: feat: add sheet management system for vaults - Add Sheet struct with holder, inputs, and mapping functionality - Implement SheetData with serialization support - Add sheets.rs with vault sheet management methods: - Load all sheets in vault - Search for sheet names - Read individual sheets - Create new sheets with validation - Delete sheets (both permanently and safely to trash) - Restore sheets from trash - Update data module to include sheet submodule - Minor fixes and improvements to related modules --- crates/vcs/src/data/sheet.rs | 109 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 crates/vcs/src/data/sheet.rs (limited to 'crates/vcs/src/data/sheet.rs') diff --git a/crates/vcs/src/data/sheet.rs b/crates/vcs/src/data/sheet.rs new file mode 100644 index 0000000..3acc8ff --- /dev/null +++ b/crates/vcs/src/data/sheet.rs @@ -0,0 +1,109 @@ +use std::{collections::HashMap, path::PathBuf}; + +use cfg_file::{ConfigFile, config::ConfigFile}; +use serde::{Deserialize, Serialize}; + +use crate::{ + constants::SERVER_FILE_SHEET, + data::{ + member::MemberId, + vault::{Vault, virtual_file::VirtualFileId}, + }, +}; + +pub type SheetName = String; +pub type SheetPathBuf = PathBuf; +pub type InputName = String; +pub type InputPackage = (InputName, Vec<(InputRaltivePathBuf, VirtualFileId)>); +pub type InputRaltivePathBuf = PathBuf; + +const SHEET_NAME: &str = "{sheet-name}"; + +pub struct Sheet<'a> { + /// The name of the current sheet + pub(crate) name: SheetName, + + /// Sheet data + pub(crate) data: SheetData, + + /// Sheet path + pub(crate) vault_reference: &'a Vault, +} + +#[derive(Default, Serialize, Deserialize, ConfigFile)] +pub struct SheetData { + /// The holder of the current sheet, who has full operation rights to the sheet mapping + pub(crate) holder: MemberId, + + /// Inputs + pub(crate) inputs: Vec, + + /// Mapping of sheet paths to virtual file IDs + pub(crate) mapping: HashMap, +} + +impl<'a> Sheet<'a> { + /// Get the holder of this sheet + pub fn holder(&self) -> &MemberId { + &self.data.holder + } + + /// Get the inputs of this sheet + pub fn inputs(&self) -> &Vec { + &self.data.inputs + } + + /// Get the mapping of this sheet + pub fn mapping(&self) -> &HashMap { + &self.data.mapping + } + + /// Add an input package to the sheet + pub fn add_input( + &mut self, + input_name: InputName, + files: Vec<(InputRaltivePathBuf, VirtualFileId)>, + ) { + self.data.inputs.push((input_name, files)); + } + + /// Remove an input package from the sheet + pub fn remove_input(&mut self, input_name: &InputName) -> Option { + self.data + .inputs + .iter() + .position(|(name, _)| name == input_name) + .map(|pos| self.data.inputs.remove(pos)) + } + + /// Add a mapping entry to the sheet + pub fn add_mapping(&mut self, sheet_path: SheetPathBuf, virtual_file_id: VirtualFileId) { + self.data.mapping.insert(sheet_path, virtual_file_id); + } + + /// Remove a mapping entry from the sheet + pub fn remove_mapping(&mut self, sheet_path: &SheetPathBuf) -> Option { + self.data.mapping.remove(sheet_path) + } + + /// Persist the sheet to disk + /// + /// Why not use a reference? + /// Because I don't want a second instance of the sheet to be kept in memory. + /// If needed, please deserialize and reload it. + pub async fn persist(self) -> Result<(), std::io::Error> { + SheetData::write_to(&self.data, &self.sheet_path()).await + } + + /// Get the path to the sheet file + pub fn sheet_path(&self) -> PathBuf { + Sheet::sheet_path_with_name(self.vault_reference, &self.name) + } + + /// Get the path to the sheet file with the given name + pub fn sheet_path_with_name(vault: &Vault, name: impl AsRef) -> PathBuf { + vault + .vault_path() + .join(SERVER_FILE_SHEET.replace(SHEET_NAME, name.as_ref())) + } +} -- cgit