viewpoint_core/page/file_chooser/
mod.rs1use std::path::Path;
8use std::sync::Arc;
9
10use viewpoint_cdp::protocol::dom::SetFileInputFilesParams;
11use viewpoint_cdp::CdpConnection;
12use tracing::{debug, instrument};
13
14use crate::error::LocatorError;
15
16#[derive(Debug)]
39pub struct FileChooser {
40 connection: Arc<CdpConnection>,
42 session_id: String,
44 frame_id: String,
46 backend_node_id: Option<i32>,
48 is_multiple: bool,
50}
51
52impl FileChooser {
53 pub(crate) fn new(
55 connection: Arc<CdpConnection>,
56 session_id: String,
57 frame_id: String,
58 backend_node_id: Option<i32>,
59 is_multiple: bool,
60 ) -> Self {
61 Self {
62 connection,
63 session_id,
64 frame_id,
65 backend_node_id,
66 is_multiple,
67 }
68 }
69
70 pub fn is_multiple(&self) -> bool {
72 self.is_multiple
73 }
74
75 #[instrument(level = "debug", skip(self, files), fields(file_count = files.len()))]
87 pub async fn set_files<P: AsRef<Path>>(&self, files: &[P]) -> Result<(), LocatorError> {
88 if !self.is_multiple && files.len() > 1 {
89 return Err(LocatorError::EvaluationError(
90 "Cannot set multiple files on a single file input".to_string(),
91 ));
92 }
93
94 let file_paths: Vec<String> = files
95 .iter()
96 .map(|p| p.as_ref().to_string_lossy().into_owned())
97 .collect();
98
99 debug!("Setting {} files on file input", file_paths.len());
100
101 self.connection
102 .send_command::<_, serde_json::Value>(
103 "DOM.setFileInputFiles",
104 Some(SetFileInputFilesParams {
105 files: file_paths,
106 node_id: None,
107 backend_node_id: self.backend_node_id,
108 object_id: None,
109 }),
110 Some(&self.session_id),
111 )
112 .await?;
113
114 Ok(())
115 }
116}
117
118#[derive(Debug, Clone)]
120pub struct FilePayload {
121 pub name: String,
123 pub mime_type: String,
125 pub buffer: Vec<u8>,
127}
128
129impl FilePayload {
130 pub fn new(name: impl Into<String>, mime_type: impl Into<String>, buffer: Vec<u8>) -> Self {
132 Self {
133 name: name.into(),
134 mime_type: mime_type.into(),
135 buffer,
136 }
137 }
138
139 pub fn from_text(name: impl Into<String>, content: impl Into<String>) -> Self {
141 Self {
142 name: name.into(),
143 mime_type: "text/plain".to_string(),
144 buffer: content.into().into_bytes(),
145 }
146 }
147
148 pub fn from_json(name: impl Into<String>, content: impl Into<String>) -> Self {
150 Self {
151 name: name.into(),
152 mime_type: "application/json".to_string(),
153 buffer: content.into().into_bytes(),
154 }
155 }
156
157 pub fn from_html(name: impl Into<String>, content: impl Into<String>) -> Self {
159 Self {
160 name: name.into(),
161 mime_type: "text/html".to_string(),
162 buffer: content.into().into_bytes(),
163 }
164 }
165}