1use std::{borrow::BorrowMut, collections::BTreeMap, fmt::Display};
2
3use crate::{
4 constants::ACTION_ITEM_BEGIN_FLOW,
5 types::{stores::AddonDefaults, types::RunbookCompleteAdditionalInfo},
6};
7
8use super::{
9 block_id::BlockId,
10 diagnostics::Diagnostic,
11 types::{Type, Value},
12 ConstructDid, Did,
13};
14use serde::Serialize;
15use uuid::Uuid;
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub enum BlockEvent {
19 Action(Block),
20 Clear,
21 UpdateActionItems(Vec<NormalizedActionItemRequestUpdate>),
22 RunbookCompleted(Vec<RunbookCompleteAdditionalInfo>),
23 Exit,
24 LogEvent(LogEvent),
25 Modal(Block),
26 Error(Block),
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
30pub enum LogLevel {
31 Trace,
32 Debug,
33 Info,
34 Warn,
35 Error,
36}
37impl ToString for LogLevel {
38 fn to_string(&self) -> String {
39 match self {
40 LogLevel::Trace => "trace".to_string(),
41 LogLevel::Debug => "debug".to_string(),
42 LogLevel::Info => "info".to_string(),
43 LogLevel::Warn => "warn".to_string(),
44 LogLevel::Error => "error".to_string(),
45 }
46 }
47}
48impl From<&str> for LogLevel {
49 fn from(s: &str) -> Self {
50 match s.to_lowercase().as_str() {
51 "trace" => LogLevel::Trace,
52 "debug" => LogLevel::Debug,
53 "info" => LogLevel::Info,
54 "warn" => LogLevel::Warn,
55 "error" => LogLevel::Error,
56 _ => LogLevel::Info,
57 }
58 }
59}
60
61impl From<String> for LogLevel {
62 fn from(s: String) -> Self {
63 LogLevel::from(s.as_str())
64 }
65}
66
67impl LogLevel {
68 pub fn should_log(&self, level: &LogLevel) -> bool {
69 level >= self
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74#[serde(tag = "type", content = "log")]
75pub enum LogEvent {
76 Static(StaticLogEvent),
77 Transient(TransientLogEvent),
78}
79
80impl LogEvent {
81 pub fn typing(&self) -> String {
82 match self {
83 LogEvent::Static(_) => "Static".into(),
84 LogEvent::Transient(_) => "Transient".into(),
85 }
86 }
87 pub fn uuid(&self) -> Uuid {
88 match self {
89 LogEvent::Static(event) => event.uuid,
90 LogEvent::Transient(event) => event.uuid,
91 }
92 }
93 pub fn status(&self) -> Option<String> {
94 match self {
95 LogEvent::Static(_) => None,
96 LogEvent::Transient(event) => Some(event.status()),
97 }
98 }
99 pub fn summary(&self) -> String {
100 match self {
101 LogEvent::Static(event) => event.details.summary.clone(),
102 LogEvent::Transient(event) => event.summary(),
103 }
104 }
105 pub fn message(&self) -> String {
106 match self {
107 LogEvent::Static(event) => event.details.message.clone(),
108 LogEvent::Transient(event) => event.message(),
109 }
110 }
111
112 pub fn level(&self) -> LogLevel {
113 match self {
114 LogEvent::Static(event) => event.level.clone(),
115 LogEvent::Transient(event) => event.level.clone(),
116 }
117 }
118
119 pub fn namespace(&self) -> &str {
120 match self {
121 LogEvent::Static(event) => &event.namespace,
122 LogEvent::Transient(event) => &event.namespace,
123 }
124 }
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize)]
128#[serde(rename_all = "camelCase")]
129pub struct StaticLogEvent {
130 pub level: LogLevel,
131 pub uuid: Uuid,
132 pub details: LogDetails,
133 pub namespace: String,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub struct LogDetails {
139 pub message: String,
140 pub summary: String,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
144#[serde(tag = "status", content = "details")]
145pub enum TransientLogEventStatus {
146 Pending(LogDetails),
147 Success(LogDetails),
148 Failure(LogDetails),
149}
150
151#[derive(Debug, Clone, Serialize, Deserialize)]
152#[serde(rename_all = "camelCase")]
153pub struct TransientLogEvent {
154 pub level: LogLevel,
155 pub uuid: Uuid,
156 pub status: TransientLogEventStatus,
157 pub namespace: String,
158}
159
160impl TransientLogEvent {
161 pub fn summary(&self) -> String {
162 match &self.status {
163 TransientLogEventStatus::Pending(log_details) => log_details.summary.clone(),
164 TransientLogEventStatus::Success(log_details) => log_details.summary.clone(),
165 TransientLogEventStatus::Failure(log_details) => log_details.summary.clone(),
166 }
167 }
168 pub fn message(&self) -> String {
169 match &self.status {
170 TransientLogEventStatus::Pending(log_details) => log_details.message.clone(),
171 TransientLogEventStatus::Success(log_details) => log_details.message.clone(),
172 TransientLogEventStatus::Failure(log_details) => log_details.message.clone(),
173 }
174 }
175 pub fn status(&self) -> String {
176 match &self.status {
177 TransientLogEventStatus::Pending(_) => "Pending".into(),
178 TransientLogEventStatus::Success(_) => "Success".into(),
179 TransientLogEventStatus::Failure(_) => "Failure".into(),
180 }
181 }
182}
183
184impl TransientLogEvent {
185 pub fn pending_info(
186 uuid: Uuid,
187 summary: impl ToString,
188 message: impl ToString,
189 namespace: impl ToString,
190 ) -> Self {
191 TransientLogEvent {
192 level: LogLevel::Info,
193 uuid,
194 status: TransientLogEventStatus::Pending(LogDetails {
195 message: message.to_string(),
196 summary: summary.to_string(),
197 }),
198 namespace: namespace.to_string(),
199 }
200 }
201
202 pub fn success_info(
203 uuid: Uuid,
204 summary: impl ToString,
205 message: impl ToString,
206 namespace: impl ToString,
207 ) -> Self {
208 TransientLogEvent {
209 level: LogLevel::Info,
210 uuid,
211 status: TransientLogEventStatus::Success(LogDetails {
212 message: message.to_string(),
213 summary: summary.to_string(),
214 }),
215 namespace: namespace.to_string(),
216 }
217 }
218
219 pub fn failure_info(
220 uuid: Uuid,
221 summary: impl ToString,
222 message: impl ToString,
223 namespace: impl ToString,
224 ) -> Self {
225 TransientLogEvent {
226 level: LogLevel::Error,
227 uuid,
228 status: TransientLogEventStatus::Failure(LogDetails {
229 message: message.to_string(),
230 summary: summary.to_string(),
231 }),
232 namespace: namespace.to_string(),
233 }
234 }
235}
236
237pub struct LogDispatcher {
238 uuid: Uuid,
239 namespace: String,
240 tx: channel::Sender<BlockEvent>,
241}
242impl LogDispatcher {
243 pub fn new(uuid: Uuid, namespace: &str, tx: &channel::Sender<BlockEvent>) -> Self {
244 LogDispatcher { uuid, namespace: format!("txtx::{}", namespace), tx: tx.clone() }
245 }
246
247 fn log_static(&self, level: LogLevel, summary: impl ToString, message: impl ToString) {
248 let _ = self.tx.try_send(BlockEvent::static_log(
249 level,
250 self.uuid,
251 self.namespace.clone(),
252 summary,
253 message,
254 ));
255 }
256
257 pub fn trace(&self, summary: impl ToString, message: impl ToString) {
258 self.log_static(LogLevel::Trace, summary, message);
259 }
260
261 pub fn debug(&self, summary: impl ToString, message: impl ToString) {
262 self.log_static(LogLevel::Debug, summary, message);
263 }
264
265 pub fn info(&self, summary: impl ToString, message: impl ToString) {
266 self.log_static(LogLevel::Info, summary, message);
267 }
268
269 pub fn warn(&self, summary: impl ToString, message: impl ToString) {
270 self.log_static(LogLevel::Warn, summary, message);
271 }
272
273 pub fn error(&self, summary: impl ToString, message: impl ToString) {
274 self.log_static(LogLevel::Error, summary, message);
275 }
276
277 pub fn pending_info(&self, summary: impl ToString, message: impl ToString) {
278 let _ = self.tx.try_send(BlockEvent::LogEvent(LogEvent::Transient(
279 TransientLogEvent::pending_info(self.uuid, summary, message, &self.namespace),
280 )));
281 }
282
283 pub fn success_info(&self, summary: impl ToString, message: impl ToString) {
284 let _ = self.tx.try_send(BlockEvent::LogEvent(LogEvent::Transient(
285 TransientLogEvent::success_info(self.uuid, summary, message, &self.namespace),
286 )));
287 }
288
289 pub fn failure_info(&self, summary: impl ToString, message: impl ToString) {
290 let _ = self.tx.try_send(BlockEvent::LogEvent(LogEvent::Transient(
291 TransientLogEvent::failure_info(self.uuid, summary, message, &self.namespace),
292 )));
293 }
294 pub fn failure_with_diag(
295 &self,
296 summary: impl ToString,
297 message: impl ToString,
298 diag: &Diagnostic,
299 ) {
300 let summary = summary.to_string();
301 self.failure_info(&summary, message);
302 self.error(summary, diag.to_string());
303 }
304}
305
306impl BlockEvent {
307 pub fn static_log(
308 level: LogLevel,
309 uuid: Uuid,
310 namespace: String,
311 summary: impl ToString,
312 message: impl ToString,
313 ) -> Self {
314 BlockEvent::LogEvent(LogEvent::Static(StaticLogEvent {
315 level,
316 uuid,
317 details: LogDetails { message: message.to_string(), summary: summary.to_string() },
318 namespace,
319 }))
320 }
321
322 pub fn transient_log(event: TransientLogEvent) -> Self {
323 BlockEvent::LogEvent(LogEvent::Transient(event))
324 }
325 pub fn as_block(&self) -> Option<&Block> {
326 match &self {
327 BlockEvent::Action(ref block) => Some(block),
328 _ => None,
329 }
330 }
331
332 pub fn as_modal(&self) -> Option<&Block> {
333 match &self {
334 BlockEvent::Modal(ref block) => Some(block),
335 _ => None,
336 }
337 }
338
339 pub fn expect_block(&self) -> &Block {
340 match &self {
341 BlockEvent::Action(ref block) => block,
342 _ => unreachable!("block expected"),
343 }
344 }
345
346 pub fn expect_modal(&self) -> &Block {
347 match &self {
348 BlockEvent::Modal(ref block) => block,
349 _ => unreachable!("block expected"),
350 }
351 }
352
353 pub fn expect_updated_action_items(&self) -> &Vec<NormalizedActionItemRequestUpdate> {
354 match &self {
355 BlockEvent::UpdateActionItems(ref updates) => updates,
356 _ => unreachable!("block expected"),
357 }
358 }
359
360 pub fn expect_runbook_completed(&self) {
361 match &self {
362 BlockEvent::RunbookCompleted(_) => {}
363 _ => unreachable!("block expected"),
364 }
365 }
366
367 pub fn expect_log_event(&self) -> &LogEvent {
368 match &self {
369 BlockEvent::LogEvent(ref log_event) => log_event,
370 _ => unreachable!("log event expected"),
371 }
372 }
373
374 pub fn new_modal(title: &str, description: &str, groups: Vec<ActionGroup>) -> Block {
375 Block {
376 uuid: Uuid::new_v4(),
377 panel: Panel::new_modal_panel(title, description, groups),
378 visible: false,
379 }
380 }
381}
382
383pub enum RunbookExecutionState {
384 RunbookGenesis,
385 RunbookGlobalsUpdated,
386}
387
388#[derive(Debug, Clone, Serialize, Deserialize)]
389#[serde(rename_all = "camelCase")]
390pub struct Block {
391 pub uuid: Uuid,
392 #[serde(flatten)]
393 pub panel: Panel,
394 pub visible: bool,
395}
396
397impl Block {
398 pub fn new(uuid: &Uuid, panel: Panel) -> Self {
399 Block { uuid: uuid.clone(), panel, visible: true }
400 }
401
402 pub fn apply_action_item_updates(&mut self, update: NormalizedActionItemRequestUpdate) -> bool {
403 let mut did_update = false;
404 match self.panel.borrow_mut() {
405 Panel::ActionPanel(panel) => {
406 for group in panel.groups.iter_mut() {
407 let group_did_update = group.apply_action_item_updates(&update);
408 if group_did_update {
409 did_update = true;
410 }
411 }
412 }
413 Panel::ModalPanel(panel) => {
414 for group in panel.groups.iter_mut() {
415 let group_did_update = group.apply_action_item_updates(&update);
416 if group_did_update {
417 did_update = true;
418 }
419 }
420 }
421 _ => {}
422 };
423 did_update
424 }
425}
426
427#[derive(Debug, Clone, Serialize, Deserialize)]
428pub struct NormalizedActionItemRequestUpdate {
431 pub id: BlockId,
432 pub action_status: Option<ActionItemStatus>,
433 pub action_type: Option<ActionItemRequestType>,
434}
435
436#[derive(Debug, Clone, Serialize)]
437pub struct ActionItemRequestUpdate {
438 pub id: ActionItemRequestUpdateIdentifier,
439 pub action_status: Option<ActionItemStatus>,
440 pub action_type: Option<ActionItemRequestType>,
441}
442
443#[derive(Debug, Clone, Serialize)]
444pub enum ActionItemRequestUpdateIdentifier {
445 Id(BlockId),
446 ConstructDidWithKey((ConstructDid, String)),
447}
448
449impl ActionItemRequestUpdate {
450 pub fn from_id(id: &BlockId) -> Self {
451 ActionItemRequestUpdate {
452 id: ActionItemRequestUpdateIdentifier::Id(id.clone()),
453 action_status: None,
454 action_type: None,
455 }
456 }
457 pub fn from_context(construct_did: &ConstructDid, internal_key: &str) -> Self {
458 ActionItemRequestUpdate {
459 id: ActionItemRequestUpdateIdentifier::ConstructDidWithKey((
460 construct_did.clone(),
461 internal_key.to_string(),
462 )),
463 action_status: None,
464 action_type: None,
465 }
466 }
467 pub fn from_diff(
472 new_item: &ActionItemRequest,
473 existing_item: &ActionItemRequest,
474 ) -> Option<Self> {
475 let id_match = new_item.id == existing_item.id;
476 let status_match = new_item.action_status == existing_item.action_status;
477 let type_diff = ActionItemRequestType::diff_mutable_properties(
478 &new_item.action_type,
479 &existing_item.action_type,
480 );
481 if !id_match || (status_match && type_diff.is_none()) {
482 return None;
483 }
484 let mut update = ActionItemRequestUpdate::from_id(&new_item.id);
485 if !status_match {
486 update.set_status(new_item.action_status.clone());
487 }
488 if let Some(new_type) = type_diff {
489 update.set_type(new_type);
490 }
491 Some(update)
492 }
493
494 pub fn set_status(&mut self, new_status: ActionItemStatus) -> Self {
495 self.action_status = Some(new_status);
496 self.clone()
497 }
498
499 pub fn set_type(&mut self, new_type: ActionItemRequestType) -> Self {
500 self.action_type = Some(new_type);
501 self.clone()
502 }
503
504 pub fn normalize(
505 &self,
506 action_item_requests: &BTreeMap<BlockId, ActionItemRequest>,
507 ) -> Option<NormalizedActionItemRequestUpdate> {
508 for (_, action) in action_item_requests.iter() {
509 match &self.id {
510 ActionItemRequestUpdateIdentifier::Id(id) => {
511 if action.id.eq(id) {
512 return Some(NormalizedActionItemRequestUpdate {
513 id: id.clone(),
514 action_status: self.action_status.clone(),
515 action_type: self.action_type.clone(),
516 });
517 }
518 }
519 ActionItemRequestUpdateIdentifier::ConstructDidWithKey((
520 construct_did,
521 internal_key,
522 )) => {
523 let Some(ref action_construct_did) = action.construct_did else {
524 continue;
525 };
526 if action_construct_did.eq(construct_did)
527 && action.internal_key.eq(internal_key)
528 {
529 return Some(NormalizedActionItemRequestUpdate {
530 id: action.id.clone(),
531 action_status: self.action_status.clone(),
532 action_type: self.action_type.clone(),
533 });
534 }
535 }
536 }
537 }
538 None
539 }
540}
541
542impl Display for Block {
543 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
544 writeln!(f, "Block {} {{", self.uuid)?;
545 match &self.panel {
546 Panel::ActionPanel(panel) => {
547 writeln!(f, " title: {}", panel.title)?;
548 for group in panel.groups.iter() {
549 writeln!(f, " group: {} {{", group.title)?;
550 for sub_group in group.sub_groups.iter() {
551 writeln!(f, " sub_group: {{")?;
552 for item in sub_group.action_items.iter() {
553 writeln!(f, " title: {:?}", item.construct_instance_name)?;
554 writeln!(f, " consctruct: {:?}", item.construct_did)?;
555 writeln!(f, " status: {:?}", item.action_status)?;
556 writeln!(f, " action: {:?}", item.action_type)?;
557 writeln!(f, " }}")?;
558 }
559 writeln!(f, " }}")?;
560 }
561 writeln!(f, " }}")?;
562 }
563 writeln!(f, "}}")
564 }
565 Panel::ModalPanel(panel) => {
566 writeln!(f, " title: {}", panel.title)?;
567 for group in panel.groups.iter() {
568 writeln!(f, " group: {} {{", group.title)?;
569 for sub_group in group.sub_groups.iter() {
570 writeln!(f, " sub_group: {{")?;
571 for item in sub_group.action_items.iter() {
572 writeln!(f, " title: {:?}", item.construct_instance_name)?;
573 writeln!(f, " consctruct: {:?}", item.construct_did)?;
574 writeln!(f, " status: {:?}", item.action_status)?;
575 writeln!(f, " action: {:?}", item.action_type)?;
576 writeln!(f, " }}")?;
577 }
578 writeln!(f, " }}")?;
579 }
580 writeln!(f, " }}")?;
581 }
582 writeln!(f, "}}")
583 }
584
585 _ => {
586 writeln!(f, "?????")
587 }
588 }
589 }
590}
591
592#[derive(Debug, Clone, Serialize, Deserialize)]
593#[serde(tag = "type", content = "panel")]
594pub enum Panel {
595 ActionPanel(ActionPanelData),
596 ModalPanel(ModalPanelData),
597 ErrorPanel(ErrorPanelData),
598}
599
600impl Panel {
601 pub fn new_action_panel(title: &str, description: &str, groups: Vec<ActionGroup>) -> Self {
602 Panel::ActionPanel(ActionPanelData {
603 title: title.to_string(),
604 description: description.to_string(),
605 groups,
606 })
607 }
608
609 pub fn new_modal_panel(title: &str, description: &str, groups: Vec<ActionGroup>) -> Self {
610 Panel::ModalPanel(ModalPanelData {
611 title: title.to_string(),
612 description: description.to_string(),
613 groups,
614 })
615 }
616
617 pub fn as_action_panel(&self) -> Option<&ActionPanelData> {
618 match &self {
619 Panel::ActionPanel(ref data) => Some(data),
620 _ => None,
621 }
622 }
623
624 pub fn as_modal_panel(&self) -> Option<&ModalPanelData> {
625 match &self {
626 Panel::ModalPanel(ref data) => Some(data),
627 _ => None,
628 }
629 }
630
631 pub fn expect_action_panel(&self) -> &ActionPanelData {
632 match &self {
633 Panel::ActionPanel(ref data) => data,
634 _ => panic!("expected action panel, got {:?}", self),
635 }
636 }
637
638 pub fn expect_modal_panel(&self) -> &ModalPanelData {
639 match &self {
640 Panel::ModalPanel(ref data) => data,
641 _ => panic!("expected action panel, got {:?}", self),
642 }
643 }
644
645 pub fn expect_modal_panel_mut(&mut self) -> &mut ModalPanelData {
646 match self {
647 Panel::ModalPanel(ref mut data) => data,
648 _ => panic!("expected action panel, got {:?}", self),
649 }
650 }
651}
652
653#[derive(Debug, Clone, Serialize, Deserialize)]
654#[serde(rename_all = "camelCase")]
655pub struct ActionPanelData {
656 pub title: String,
657 pub description: String,
658 pub groups: Vec<ActionGroup>,
659}
660
661impl ActionPanelData {
662 pub fn compile_actions_to_item_updates(
663 &self,
664 action_item_requests: &BTreeMap<BlockId, ActionItemRequest>,
665 ) -> Vec<ActionItemRequestUpdate> {
666 let mut updates = vec![];
667 for group in self.groups.iter() {
668 let mut group_updates = group.compile_actions_to_item_updates(&action_item_requests);
669 updates.append(&mut group_updates);
670 }
671 updates
672 }
673
674 pub fn filter_existing_action_items(
675 &mut self,
676 existing_requests: &Vec<&mut ActionItemRequest>,
677 ) -> &mut Self {
678 let mut group_idx_to_remove = vec![];
679 for (i, group) in self.groups.iter_mut().enumerate() {
680 group.filter_existing_action_items(&existing_requests);
681 if group.sub_groups.is_empty() {
682 group_idx_to_remove.push(i);
683 }
684 }
685 group_idx_to_remove.iter().rev().for_each(|i| {
686 self.groups.remove(*i);
687 });
688 self
689 }
690}
691
692#[derive(Debug, Clone, Serialize, Deserialize)]
693#[serde(rename_all = "camelCase")]
694pub struct ModalPanelData {
695 pub title: String,
696 pub description: String,
697 pub groups: Vec<ActionGroup>,
698}
699
700impl ModalPanelData {
701 pub fn compile_actions_to_item_updates(
702 &self,
703 action_item_requests: &BTreeMap<BlockId, ActionItemRequest>,
704 ) -> Vec<ActionItemRequestUpdate> {
705 let mut updates = vec![];
706 for group in self.groups.iter() {
707 let mut group_updates = group.compile_actions_to_item_updates(&action_item_requests);
708 updates.append(&mut group_updates);
709 }
710 updates
711 }
712
713 pub fn filter_existing_action_items(
714 &mut self,
715 existing_requests: &Vec<&mut ActionItemRequest>,
716 ) -> &mut Self {
717 let mut group_idx_to_remove = vec![];
718 for (i, group) in self.groups.iter_mut().enumerate() {
719 group.filter_existing_action_items(&existing_requests);
720 if group.sub_groups.is_empty() {
721 group_idx_to_remove.push(i);
722 }
723 }
724 group_idx_to_remove.iter().rev().for_each(|i| {
725 self.groups.remove(*i);
726 });
727 self
728 }
729}
730
731#[derive(Debug, Clone, Serialize, Deserialize)]
732#[serde(rename_all = "camelCase")]
733pub struct ErrorPanelData {
734 pub title: String,
735 pub description: String,
736 pub groups: Vec<ActionGroup>,
737}
738
739impl ErrorPanelData {
740 pub fn from_diagnostics(diagnostics: &Vec<Diagnostic>) -> Self {
741 let mut diag_actions = vec![];
742 for (i, diag) in diagnostics.iter().enumerate() {
743 let mut action = ActionItemRequestType::DisplayErrorLog(DisplayErrorLogRequest {
744 diagnostic: diag.clone(),
745 })
746 .to_request("", "diagnostic")
747 .with_status(ActionItemStatus::Error(diag.clone()));
748
749 action.index = (i + 1) as u16;
750 diag_actions.push(action);
751 }
752 ErrorPanelData {
753 title: "EXECUTION ERROR".into(),
754 description: "Review the following execution errors and restart the runbook.".into(),
755 groups: vec![ActionGroup {
756 title: "".into(),
757 sub_groups: vec![ActionSubGroup {
758 title: None,
759 action_items: diag_actions,
760 allow_batch_completion: false,
761 }],
762 }],
763 }
764 }
765}
766
767#[derive(Debug, Clone, Serialize, Deserialize)]
768#[serde(rename_all = "camelCase")]
769pub struct ActionGroup {
770 pub title: String,
771 pub sub_groups: Vec<ActionSubGroup>,
772}
773
774impl ActionGroup {
775 pub fn new(title: &str, sub_groups: Vec<ActionSubGroup>) -> Self {
776 ActionGroup { title: title.to_string(), sub_groups }
777 }
778 pub fn contains_validate_modal_item(&self) -> bool {
779 for sub_group in self.sub_groups.iter() {
780 for item in sub_group.action_items.iter() {
781 if let ActionItemRequestType::ValidateModal = item.action_type {
782 return true;
783 }
784 }
785 }
786 false
787 }
788
789 pub fn apply_action_item_updates(
790 &mut self,
791 update: &NormalizedActionItemRequestUpdate,
792 ) -> bool {
793 let mut did_update = false;
794 for sub_group in self.sub_groups.iter_mut() {
795 for action in sub_group.action_items.iter_mut() {
796 if action.id == update.id {
797 if let Some(action_status) = update.action_status.clone() {
798 if action.action_status != action_status {
799 action.action_status = action_status;
800 did_update = true;
801 }
802 }
803 if let Some(action_type) = update.action_type.clone() {
804 if action.action_type != action_type {
805 action.action_type = action_type;
806 did_update = true;
807 }
808 }
809 }
810 }
811 }
812 did_update
813 }
814
815 pub fn compile_actions_to_item_updates(
816 &self,
817 action_item_requests: &BTreeMap<BlockId, ActionItemRequest>,
818 ) -> Vec<ActionItemRequestUpdate> {
819 let mut updates = vec![];
820 for sub_group in self.sub_groups.iter() {
821 let mut sub_group_updates =
822 sub_group.compile_actions_to_item_updates(&action_item_requests);
823 updates.append(&mut sub_group_updates);
824 }
825 updates
826 }
827
828 pub fn filter_existing_action_items(
829 &mut self,
830 existing_requests: &Vec<&mut ActionItemRequest>,
831 ) -> &mut Self {
832 let mut sub_group_idx_to_remove = vec![];
833 for (i, sub_group) in self.sub_groups.iter_mut().enumerate() {
834 sub_group.filter_existing_action_items(&existing_requests);
835 if sub_group.action_items.is_empty() {
836 sub_group_idx_to_remove.push(i);
837 }
838 }
839 sub_group_idx_to_remove.iter().rev().for_each(|i| {
840 self.sub_groups.remove(*i);
841 });
842 self
843 }
844}
845
846#[derive(Debug, Clone, Serialize, Deserialize)]
847#[serde(rename_all = "camelCase")]
848pub struct ActionSubGroup {
849 pub title: Option<String>,
850 pub action_items: Vec<ActionItemRequest>,
851 pub allow_batch_completion: bool,
852}
853
854impl ActionSubGroup {
855 pub fn new(
856 title: Option<String>,
857 action_items: Vec<ActionItemRequest>,
858 allow_batch_completion: bool,
859 ) -> Self {
860 ActionSubGroup { title, action_items, allow_batch_completion }
861 }
862
863 pub fn contains_validate_modal_item(&self) -> bool {
864 for item in self.action_items.iter() {
865 if let ActionItemRequestType::ValidateModal = item.action_type {
866 return true;
867 }
868 }
869 false
870 }
871
872 pub fn compile_actions_to_item_updates(
873 &self,
874 action_item_requests: &BTreeMap<BlockId, ActionItemRequest>,
875 ) -> Vec<ActionItemRequestUpdate> {
876 let mut updates = vec![];
877 for new_item in self.action_items.iter() {
878 if let Some(existing_item) = action_item_requests.get(&new_item.id) {
879 if let Some(update) = ActionItemRequestUpdate::from_diff(new_item, existing_item) {
880 updates.push(update);
881 };
882 };
883 }
884 updates
885 }
886
887 pub fn filter_existing_action_items(
888 &mut self,
889 existing_requests: &Vec<&mut ActionItemRequest>,
890 ) -> &mut Self {
891 let mut action_item_idx_to_remove = vec![];
892 for (i, new_item) in self.action_items.iter().enumerate() {
893 for existing_item in existing_requests.iter() {
894 if existing_item.id.eq(&new_item.id) {
895 if let None = ActionItemRequestUpdate::from_diff(new_item, existing_item) {
896 action_item_idx_to_remove.push(i);
897 };
898 }
899 }
900 }
901 action_item_idx_to_remove.iter().rev().for_each(|i| {
902 self.action_items.remove(*i);
903 });
904 self
905 }
906}
907
908#[derive(Debug, Clone, Serialize, Deserialize)]
909#[serde(rename_all = "camelCase")]
910pub struct ActionItemRequest {
911 pub id: BlockId,
912 pub construct_did: Option<ConstructDid>,
913 pub index: u16,
914 pub construct_instance_name: String,
915 pub meta_description: Option<String>,
916 pub description: Option<String>,
917 pub markdown: Option<String>,
918 pub action_status: ActionItemStatus,
919 pub action_type: ActionItemRequestType,
920 pub internal_key: String,
921}
922
923impl ActionItemRequest {
924 fn new(
925 construct_instance_name: &str,
926 internal_key: &str,
927 action_type: ActionItemRequestType,
928 ) -> Self {
929 let mut req = ActionItemRequest {
930 id: BlockId::new("empty".as_bytes()),
931 construct_did: None,
932 index: 0,
933 construct_instance_name: construct_instance_name.to_string(),
934 description: None,
935 meta_description: None,
936 markdown: None,
937 action_status: ActionItemStatus::Todo,
938 action_type,
939 internal_key: internal_key.to_string(),
940 };
941 req.recompute_id();
942 req
943 }
944 pub fn with_description(mut self, description: &str) -> Self {
945 self.description = Some(description.to_string());
946 self.recompute_id();
947 self
948 }
949 pub fn with_some_description(mut self, description: Option<String>) -> Self {
950 self.description = description;
951 self.recompute_id();
952 self
953 }
954 pub fn with_meta_description(mut self, meta_description: &str) -> Self {
955 self.meta_description = Some(meta_description.to_string());
956 self.recompute_id();
957 self
958 }
959 pub fn with_some_meta_description(mut self, meta_description: Option<String>) -> Self {
960 self.meta_description = meta_description;
961 self
962 }
963 pub fn with_some_markdown(mut self, markdown: Option<String>) -> Self {
964 self.markdown = markdown;
965 self
966 }
967 pub fn with_construct_did(mut self, construct_did: &ConstructDid) -> Self {
968 self.construct_did = Some(construct_did.clone());
969 self.recompute_id();
970 self
971 }
972 pub fn with_status(mut self, action_status: ActionItemStatus) -> Self {
973 self.action_status = action_status;
974 self
975 }
976 pub fn recompute_id(&mut self) {
977 let data = format!(
978 "{}-{}-{}-{}-{}",
979 self.construct_instance_name,
980 self.description.clone().unwrap_or("".into()),
981 self.internal_key,
982 self.construct_did.as_ref().and_then(|did| Some(did.to_string())).unwrap_or("".into()),
983 self.action_type.get_block_id_string()
984 );
985 self.id = BlockId::new(data.as_bytes());
986 }
987}
988
989pub enum ChecklistActionResultProvider {
990 TermConsole,
991 LocalWebConsole,
992 RemoteWebConsole,
993}
994
995#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
996#[serde(tag = "status", content = "data")]
997pub enum ActionItemStatus {
998 Blocked,
999 Todo,
1000 Success(Option<String>),
1001 InProgress(String),
1002 Error(Diagnostic),
1003 Warning(Diagnostic),
1004}
1005
1006#[derive(Debug, Clone, Serialize)]
1007#[serde(rename_all = "camelCase")]
1008pub struct UpdateConstructData {
1009 pub construct_did: ConstructDid,
1010 pub action_item_update: ActionItemRequestUpdate,
1011 pub internal_key: String,
1012}
1013
1014#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1015#[serde(rename_all = "camelCase")]
1016pub struct OpenModalData {
1017 pub modal_uuid: Uuid,
1018 pub title: String,
1019}
1020
1021#[derive(Clone, Debug)]
1022pub enum ActionType {
1023 UpdateActionItemRequest(ActionItemRequestUpdate),
1024 AppendSubGroup(ActionSubGroup),
1025 AppendGroup(ActionGroup),
1026 AppendItem(ActionItemRequest, Option<String>, Option<String>),
1027 NewBlock(ActionPanelData),
1028 NewModal(Block),
1029}
1030
1031#[derive(Clone, Debug)]
1032pub struct Actions {
1033 pub store: Vec<ActionType>,
1034}
1035
1036impl Actions {
1037 pub fn none() -> Actions {
1038 Actions { store: vec![] }
1039 }
1040
1041 pub fn has_pending_actions(&self) -> bool {
1042 for item in self.store.iter() {
1043 match item {
1044 ActionType::AppendSubGroup(_)
1045 | ActionType::AppendGroup(_)
1046 | ActionType::AppendItem(_, _, _) => return true,
1047 ActionType::NewBlock(_) => return true,
1048 ActionType::NewModal(_) => return true,
1049 ActionType::UpdateActionItemRequest(data) => {
1050 match data.action_status.clone().unwrap() {
1051 ActionItemStatus::Success(_) => continue,
1052 _ => return true,
1053 }
1054 }
1055 }
1056 }
1057 false
1058 }
1059
1060 pub fn append(&mut self, actions: &mut Actions) {
1061 self.store.append(&mut actions.store);
1062 }
1063
1064 pub fn push_modal(&mut self, block: Block) {
1065 self.store.push(ActionType::NewModal(block));
1066 }
1067
1068 pub fn push_group(&mut self, title: &str, action_items: Vec<ActionItemRequest>) {
1069 self.store.push(ActionType::AppendGroup(ActionGroup {
1070 sub_groups: vec![ActionSubGroup {
1071 title: None,
1072 action_items,
1073 allow_batch_completion: false,
1074 }],
1075 title: title.to_string(),
1076 }));
1077 }
1078
1079 pub fn push_sub_group(&mut self, title: Option<String>, action_items: Vec<ActionItemRequest>) {
1080 if !action_items.is_empty() {
1081 self.store.push(ActionType::AppendSubGroup(ActionSubGroup {
1082 title,
1083 action_items,
1084 allow_batch_completion: false,
1085 }));
1086 }
1087 }
1088 pub fn push_action_item_update(&mut self, update: ActionItemRequestUpdate) {
1089 self.store.push(ActionType::UpdateActionItemRequest(update))
1090 }
1091
1092 pub fn push_panel(&mut self, title: &str, description: &str) {
1093 self.store.push(ActionType::NewBlock(ActionPanelData {
1094 title: title.to_string(),
1095 description: description.to_string(), groups: vec![],
1097 }))
1098 }
1099
1100 pub fn push_begin_flow_panel(
1101 &mut self,
1102 flow_index: usize,
1103 total_flows_count: usize,
1104 flow_name: &str,
1105 flow_description: &Option<String>,
1106 ) {
1107 self.store.push(ActionType::NewBlock(ActionPanelData {
1108 title: "Flow Execution".to_string(),
1109 description: "".to_string(),
1110 groups: vec![ActionGroup {
1111 title: "".to_string(),
1112 sub_groups: vec![ActionSubGroup {
1113 title: None,
1114 action_items: vec![ActionItemRequestType::BeginFlow(FlowBlockData {
1115 index: flow_index,
1116 total_flows: total_flows_count,
1117 name: flow_name.to_string(),
1118 description: flow_description.clone(),
1119 })
1120 .to_request("", ACTION_ITEM_BEGIN_FLOW)
1121 .with_status(ActionItemStatus::Success(None))],
1122 allow_batch_completion: false,
1123 }],
1124 }],
1125 }))
1126 }
1127
1128 pub fn new_panel(title: &str, description: &str) -> Actions {
1129 let store = vec![ActionType::NewBlock(ActionPanelData {
1130 title: title.to_string(),
1131 description: description.to_string(), groups: vec![],
1133 })];
1134 Actions { store }
1135 }
1136
1137 pub fn new_group_of_items(title: &str, action_items: Vec<ActionItemRequest>) -> Actions {
1138 let store = vec![ActionType::AppendGroup(ActionGroup {
1139 sub_groups: vec![ActionSubGroup {
1140 title: None,
1141 action_items,
1142 allow_batch_completion: false,
1143 }],
1144 title: title.to_string(),
1145 })];
1146 Actions { store }
1147 }
1148
1149 pub fn new_sub_group_of_items(
1150 title: Option<String>,
1151 action_items: Vec<ActionItemRequest>,
1152 ) -> Actions {
1153 let store = vec![ActionType::AppendSubGroup(ActionSubGroup {
1154 title,
1155 action_items,
1156 allow_batch_completion: false,
1157 })];
1158 Actions { store }
1159 }
1160
1161 pub fn append_item(
1162 item: ActionItemRequest,
1163 group_title: Option<&str>,
1164 panel_title: Option<&str>,
1165 ) -> Actions {
1166 let store = vec![ActionType::AppendItem(
1167 item,
1168 group_title.map(|t| t.to_string()),
1169 panel_title.map(|t| t.to_string()),
1170 )];
1171 Actions { store }
1172 }
1173
1174 pub fn get_new_action_item_requests(&self) -> Vec<&ActionItemRequest> {
1175 let mut new_action_item_requests = vec![];
1176 for item in self.store.iter() {
1177 match item {
1178 ActionType::AppendSubGroup(data) => {
1179 for item in data.action_items.iter() {
1180 new_action_item_requests.push(item);
1181 }
1182 }
1183 ActionType::AppendGroup(data) => {
1184 for subgroup in data.sub_groups.iter() {
1185 for item in subgroup.action_items.iter() {
1186 new_action_item_requests.push(item);
1187 }
1188 }
1189 }
1190 ActionType::AppendItem(item, _, _) => {
1191 new_action_item_requests.push(item);
1192 }
1193 ActionType::NewBlock(data) => {
1194 for group in data.groups.iter() {
1195 for subgroup in group.sub_groups.iter() {
1196 for item in subgroup.action_items.iter() {
1197 new_action_item_requests.push(item);
1198 }
1199 }
1200 }
1201 }
1202 ActionType::NewModal(data) => {
1203 for group in data.panel.expect_modal_panel().groups.iter() {
1204 for subgroup in group.sub_groups.iter() {
1205 for item in subgroup.action_items.iter() {
1206 new_action_item_requests.push(item);
1207 }
1208 }
1209 }
1210 }
1211 ActionType::UpdateActionItemRequest(_) => continue,
1212 }
1213 }
1214 new_action_item_requests
1215 }
1216
1217 pub fn compile_actions_to_block_events(
1218 &mut self,
1219 action_item_requests: &BTreeMap<BlockId, ActionItemRequest>,
1220 ) -> Vec<BlockEvent> {
1221 let mut blocks = vec![];
1222 let mut current_panel_data =
1223 ActionPanelData { title: "".to_string(), description: "".to_string(), groups: vec![] };
1224 let mut index = 0;
1225 let mut current_modal: Option<Block> = None;
1226 let mut updates = vec![];
1227 for item in self.store.iter_mut() {
1228 match item {
1229 ActionType::AppendItem(item, group_title, panel_title) => {
1230 item.index = index;
1231 index += 1;
1232 match current_modal {
1233 None => {
1234 if current_panel_data.groups.len() > 0 {
1235 let Some(group) = current_panel_data.groups.last_mut() else {
1236 continue;
1237 };
1238 if group.sub_groups.len() > 0 {
1239 let Some(sub_group) = group.sub_groups.last_mut() else {
1241 continue;
1242 };
1243 if sub_group.action_items.is_empty() {
1244 *sub_group = ActionSubGroup {
1245 title: None,
1246 action_items: vec![item.clone()],
1247 allow_batch_completion: true,
1248 };
1249 continue;
1250 }
1251 }
1252 group
1253 .sub_groups
1254 .last_mut()
1255 .unwrap()
1256 .action_items
1257 .push(item.clone());
1258 } else {
1259 current_panel_data.groups.push(ActionGroup {
1260 title: group_title.as_ref().unwrap_or(&"".into()).into(),
1261 sub_groups: vec![ActionSubGroup {
1262 title: None,
1263 action_items: vec![item.clone()],
1264 allow_batch_completion: true,
1265 }],
1266 });
1267 }
1268 if let Some(panel_title) = panel_title {
1269 current_panel_data.title = panel_title.to_string();
1270 }
1271 }
1272 Some(ref mut modal) => {
1273 if modal.panel.expect_modal_panel().groups.len() > 0 {
1274 let Some(group) =
1275 modal.panel.expect_modal_panel_mut().groups.last_mut()
1276 else {
1277 continue;
1278 };
1279 if group.sub_groups.len() > 0 {
1280 let Some(sub_group) = group.sub_groups.last_mut() else {
1282 continue;
1283 };
1284 if sub_group.action_items.is_empty() {
1285 *sub_group = ActionSubGroup {
1286 title: None,
1287 action_items: vec![item.clone()],
1288 allow_batch_completion: true,
1289 };
1290 continue;
1291 }
1292 }
1293 group.sub_groups.push(ActionSubGroup {
1294 title: None,
1295 action_items: vec![item.clone()],
1296 allow_batch_completion: true,
1297 });
1298 } else {
1299 modal.panel.expect_modal_panel_mut().groups.push(ActionGroup {
1300 title: group_title.as_ref().unwrap_or(&"".into()).into(),
1301 sub_groups: vec![ActionSubGroup {
1302 title: None,
1303 action_items: vec![item.clone()],
1304 allow_batch_completion: true,
1305 }],
1306 });
1307 }
1308 if let ActionItemRequestType::ValidateModal = item.action_type {
1309 blocks.push(BlockEvent::Modal(modal.clone()));
1310 current_modal = None;
1311 }
1312 }
1313 }
1314 }
1315 ActionType::AppendSubGroup(data) => {
1316 for item in data.action_items.iter_mut() {
1317 item.index = index;
1318 index += 1;
1319 }
1320 match current_modal {
1321 None => {
1322 if current_panel_data.groups.len() > 0 {
1323 let Some(group) = current_panel_data.groups.last_mut() else {
1324 continue;
1325 };
1326 if group.sub_groups.len() > 0 {
1327 let Some(sub_group) = group.sub_groups.last_mut() else {
1329 continue;
1330 };
1331 if sub_group.action_items.is_empty() {
1332 *sub_group = data.clone();
1333 continue;
1334 }
1335 }
1336 group.sub_groups.push(data.clone());
1337 } else {
1338 current_panel_data.groups.push(ActionGroup {
1339 title: "".to_string(),
1340 sub_groups: vec![data.clone()],
1341 });
1342 }
1343 }
1344 Some(ref mut modal) => {
1345 if modal.panel.expect_modal_panel().groups.len() > 0 {
1346 let Some(group) =
1347 modal.panel.expect_modal_panel_mut().groups.last_mut()
1348 else {
1349 continue;
1350 };
1351 if group.sub_groups.len() > 0 {
1352 let Some(sub_group) = group.sub_groups.last_mut() else {
1354 continue;
1355 };
1356 if sub_group.action_items.is_empty() {
1357 *sub_group = data.clone();
1358 continue;
1359 }
1360 }
1361 group.sub_groups.push(data.clone());
1362 } else {
1363 modal.panel.expect_modal_panel_mut().groups.push(ActionGroup {
1364 title: "".to_string(),
1365 sub_groups: vec![data.clone()],
1366 });
1367 }
1368 if data.contains_validate_modal_item() {
1369 blocks.push(BlockEvent::Modal(modal.clone()));
1370 current_modal = None;
1371 }
1372 }
1373 }
1374 }
1375 ActionType::AppendGroup(data) => {
1376 for subgroup in data.sub_groups.iter_mut() {
1377 for item in subgroup.action_items.iter_mut() {
1378 item.index = index;
1379 index += 1;
1380 }
1381 }
1382 match current_modal {
1383 None => {
1384 current_panel_data.groups.push(data.clone());
1385 }
1386 Some(ref mut modal) => {
1387 modal.panel.expect_modal_panel_mut().groups.push(data.clone());
1388 if data.contains_validate_modal_item() {
1389 blocks.push(BlockEvent::Modal(modal.clone()));
1390 current_modal = None;
1391 }
1392 }
1393 }
1394 }
1395 ActionType::NewBlock(data) => {
1396 if current_panel_data.groups.len() >= 1 {
1397 blocks.push(BlockEvent::Action(Block {
1398 uuid: Uuid::new_v4(),
1399 panel: Panel::ActionPanel(current_panel_data.clone()),
1400 visible: true,
1401 }));
1402 }
1403 current_panel_data = data.clone();
1404 }
1405 ActionType::NewModal(data) => {
1406 current_modal = Some(data.clone());
1407 }
1408 ActionType::UpdateActionItemRequest(data) => {
1409 if let Some(update) = data.normalize(&action_item_requests) {
1410 updates.push(update);
1411 }
1412 }
1413 }
1414 }
1415 if !updates.is_empty() {
1416 blocks.push(BlockEvent::UpdateActionItems(updates));
1417 }
1418 if current_panel_data.groups.len() > 0 {
1419 blocks.push(BlockEvent::Action(Block {
1420 uuid: Uuid::new_v4(),
1421 panel: Panel::ActionPanel(current_panel_data.clone()),
1422 visible: true,
1423 }));
1424 }
1425 blocks
1426 }
1427
1428 pub fn compile_actions_to_item_updates(
1429 &self,
1430 action_item_requests: &BTreeMap<BlockId, ActionItemRequest>,
1431 ) -> Vec<ActionItemRequestUpdate> {
1432 let mut updates = vec![];
1433
1434 for item in self.store.iter() {
1435 match item {
1436 ActionType::AppendSubGroup(sub_group) => {
1437 let mut sub_group_updates =
1438 sub_group.compile_actions_to_item_updates(&action_item_requests);
1439 updates.append(&mut sub_group_updates);
1440 }
1441 ActionType::AppendGroup(group) => {
1442 let mut group_updates =
1443 group.compile_actions_to_item_updates(&action_item_requests);
1444 updates.append(&mut group_updates);
1445 }
1446 ActionType::AppendItem(new_item, _, _) => {
1447 if let Some(existing_item) = action_item_requests.get(&new_item.id) {
1448 if let Some(update) =
1449 ActionItemRequestUpdate::from_diff(new_item, existing_item)
1450 {
1451 updates.push(update);
1452 };
1453 };
1454 }
1455 ActionType::NewBlock(action_panel_data) => {
1456 let mut block_updates =
1457 action_panel_data.compile_actions_to_item_updates(&action_item_requests);
1458 updates.append(&mut block_updates);
1459 }
1460 ActionType::NewModal(modal) => match &modal.panel {
1461 Panel::ActionPanel(action_panel_data) => {
1462 let mut block_updates = action_panel_data
1463 .compile_actions_to_item_updates(&action_item_requests);
1464 updates.append(&mut block_updates);
1465 }
1466 Panel::ModalPanel(modal_panel_data) => {
1467 let mut block_updates =
1468 modal_panel_data.compile_actions_to_item_updates(&action_item_requests);
1469 updates.append(&mut block_updates);
1470 }
1471 _ => {}
1472 },
1473 ActionType::UpdateActionItemRequest(update) => updates.push(update.clone()),
1474 }
1475 }
1476
1477 updates
1478 }
1479
1480 pub fn filter_existing_action_items(
1481 &mut self,
1482 existing_requests: &Option<&Vec<&mut ActionItemRequest>>,
1483 ) -> &mut Self {
1484 let Some(existing_requests) = existing_requests else {
1485 return self;
1486 };
1487
1488 let mut idx_to_remove = vec![];
1489 for (i, item) in self.store.iter_mut().enumerate() {
1490 match item {
1491 ActionType::UpdateActionItemRequest(_) => {}
1492 ActionType::AppendSubGroup(sub_group) => {
1493 sub_group.filter_existing_action_items(&existing_requests);
1494 if sub_group.action_items.is_empty() {
1495 idx_to_remove.push(i);
1496 }
1497 }
1498 ActionType::AppendGroup(group) => {
1499 group.filter_existing_action_items(&existing_requests);
1500 if group.sub_groups.is_empty() {
1501 idx_to_remove.push(i);
1502 }
1503 }
1504 ActionType::AppendItem(new_item, _, _) => {
1505 for existing_item in existing_requests.iter() {
1506 if existing_item.id.eq(&new_item.id) {
1507 if let None =
1508 ActionItemRequestUpdate::from_diff(new_item, existing_item)
1509 {
1510 idx_to_remove.push(i);
1511 };
1512 }
1513 }
1514 }
1515 ActionType::NewBlock(block) => {
1516 block.filter_existing_action_items(&existing_requests);
1517 if block.groups.is_empty() {
1518 idx_to_remove.push(i);
1519 }
1520 }
1521 ActionType::NewModal(_) => {}
1522 }
1523 }
1524 idx_to_remove.iter().rev().for_each(|i| {
1525 self.store.remove(*i);
1526 });
1527
1528 self
1529 }
1530}
1531
1532#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1533#[serde(tag = "type", content = "data")]
1534pub enum ActionItemRequestType {
1535 ReviewInput(ReviewInputRequest),
1536 ProvideInput(ProvideInputRequest),
1537 PickInputOption(PickInputOptionRequest),
1538 ProvidePublicKey(ProvidePublicKeyRequest),
1539 ProvideSignedTransaction(ProvideSignedTransactionRequest),
1540 VerifyThirdPartySignature(VerifyThirdPartySignatureRequest),
1541 ProvideSignedMessage(ProvideSignedMessageRequest),
1542 SendTransaction(SendTransactionRequest),
1543 DisplayOutput(DisplayOutputRequest),
1544 DisplayErrorLog(DisplayErrorLogRequest),
1545 OpenModal(OpenModalData),
1546 ValidateBlock(ValidateBlockData),
1547 ValidateModal,
1548 BeginFlow(FlowBlockData),
1549}
1550
1551impl ActionItemRequestType {
1552 pub fn to_request(
1553 self,
1554 construct_instance_name: &str,
1555 internal_key: &str,
1556 ) -> ActionItemRequest {
1557 ActionItemRequest::new(construct_instance_name, internal_key, self)
1558 }
1559 pub fn as_review_input(&self) -> Option<&ReviewInputRequest> {
1560 match &self {
1561 ActionItemRequestType::ReviewInput(value) => Some(value),
1562 _ => None,
1563 }
1564 }
1565 pub fn as_provide_input(&self) -> Option<&ProvideInputRequest> {
1566 match &self {
1567 ActionItemRequestType::ProvideInput(value) => Some(value),
1568 _ => None,
1569 }
1570 }
1571 pub fn as_pick_input(&self) -> Option<&PickInputOptionRequest> {
1572 match &self {
1573 ActionItemRequestType::PickInputOption(value) => Some(value),
1574 _ => None,
1575 }
1576 }
1577 pub fn as_provide_public_key(&self) -> Option<&ProvidePublicKeyRequest> {
1578 match &self {
1579 ActionItemRequestType::ProvidePublicKey(value) => Some(value),
1580 _ => None,
1581 }
1582 }
1583 pub fn as_provide_signed_tx(&self) -> Option<&ProvideSignedTransactionRequest> {
1584 match &self {
1585 ActionItemRequestType::ProvideSignedTransaction(value) => Some(value),
1586 _ => None,
1587 }
1588 }
1589 pub fn as_verify_third_party_signature(&self) -> Option<&VerifyThirdPartySignatureRequest> {
1590 match &self {
1591 ActionItemRequestType::VerifyThirdPartySignature(value) => Some(value),
1592 _ => None,
1593 }
1594 }
1595 pub fn as_sign_tx(&self) -> Option<&SendTransactionRequest> {
1596 match &self {
1597 ActionItemRequestType::SendTransaction(value) => Some(value),
1598 _ => None,
1599 }
1600 }
1601 pub fn as_provide_signed_msg(&self) -> Option<&ProvideSignedMessageRequest> {
1602 match &self {
1603 ActionItemRequestType::ProvideSignedMessage(value) => Some(value),
1604 _ => None,
1605 }
1606 }
1607 pub fn as_display_output(&self) -> Option<&DisplayOutputRequest> {
1608 match &self {
1609 ActionItemRequestType::DisplayOutput(value) => Some(value),
1610 _ => None,
1611 }
1612 }
1613 pub fn as_display_err(&self) -> Option<&DisplayErrorLogRequest> {
1614 match &self {
1615 ActionItemRequestType::DisplayErrorLog(value) => Some(value),
1616 _ => None,
1617 }
1618 }
1619 pub fn as_open_modal(&self) -> Option<&OpenModalData> {
1620 match &self {
1621 ActionItemRequestType::OpenModal(value) => Some(value),
1622 _ => None,
1623 }
1624 }
1625
1626 pub fn get_block_id_string(&self) -> String {
1630 match self {
1631 ActionItemRequestType::ReviewInput(val) => {
1632 format!("ReviewInput({}-{})", val.input_name, val.force_execution)
1633 }
1634 ActionItemRequestType::ProvideInput(val) => format!(
1635 "ProvideInput({}-{})",
1636 val.input_name,
1637 serde_json::to_string(&val.typing).unwrap() ),
1639 ActionItemRequestType::PickInputOption(_) => format!("PickInputOption"),
1640 ActionItemRequestType::ProvidePublicKey(val) => format!(
1641 "ProvidePublicKey({}-{}-{})",
1642 val.check_expectation_action_uuid
1643 .as_ref()
1644 .and_then(|u| Some(u.to_string()))
1645 .unwrap_or("None".to_string()),
1646 val.namespace,
1647 val.network_id
1648 ),
1649 ActionItemRequestType::ProvideSignedTransaction(val) => {
1650 format!(
1651 "ProvideSignedTransaction({}-{}-{}-{})",
1652 val.check_expectation_action_uuid
1653 .as_ref()
1654 .and_then(|u| Some(u.to_string()))
1655 .unwrap_or("None".to_string()),
1656 val.signer_uuid.to_string(),
1657 val.namespace,
1658 val.network_id
1659 )
1660 }
1661 ActionItemRequestType::VerifyThirdPartySignature(val) => {
1662 format!(
1663 "VerifyThirdPartySignature({}-{}-{})",
1664 val.check_expectation_action_uuid
1665 .as_ref()
1666 .and_then(|u| Some(u.to_string()))
1667 .unwrap_or("None".to_string()),
1668 val.namespace,
1669 val.network_id
1670 )
1671 }
1672 ActionItemRequestType::SendTransaction(val) => {
1673 format!(
1674 "SendTransaction({}-{}-{}-{})",
1675 val.check_expectation_action_uuid
1676 .as_ref()
1677 .and_then(|u| Some(u.to_string()))
1678 .unwrap_or("None".to_string()),
1679 val.signer_uuid.to_string(),
1680 val.namespace,
1681 val.network_id
1682 )
1683 }
1684 ActionItemRequestType::ProvideSignedMessage(val) => format!(
1685 "ProvideSignedMessage({}-{}-{}-{})",
1686 val.check_expectation_action_uuid
1687 .as_ref()
1688 .and_then(|u| Some(u.to_string()))
1689 .unwrap_or("None".to_string()),
1690 val.signer_uuid.to_string(),
1691 val.namespace,
1692 val.network_id
1693 ),
1694 ActionItemRequestType::DisplayOutput(val) => format!(
1695 "DisplayOutput({}-{}-{})",
1696 val.name,
1697 val.description.clone().unwrap_or("None".to_string()),
1698 val.value.to_string()
1699 ),
1700 ActionItemRequestType::DisplayErrorLog(val) => {
1701 format!("DisplayErrorLog({})", val.diagnostic.to_string())
1702 }
1703 ActionItemRequestType::OpenModal(val) => {
1704 format!("OpenModal({}-{})", val.modal_uuid, val.title)
1705 }
1706 ActionItemRequestType::ValidateBlock(val) => {
1707 format!("ValidateBlock({})", val.internal_idx.to_string())
1708 }
1709 ActionItemRequestType::ValidateModal => format!("ValidateModal"),
1710 ActionItemRequestType::BeginFlow(val) => {
1711 format!("BeginFlow({}-{})", val.index, val.name)
1712 }
1713 }
1714 }
1715
1716 pub fn diff_mutable_properties(
1722 new_type: &ActionItemRequestType,
1723 existing_item: &ActionItemRequestType,
1724 ) -> Option<ActionItemRequestType> {
1725 match new_type {
1726 ActionItemRequestType::ReviewInput(new) => {
1727 let Some(existing) = existing_item.as_review_input() else {
1728 unreachable!("cannot change action item request type")
1729 };
1730 if new.value != existing.value {
1731 if new.input_name != existing.input_name {
1732 unreachable!("cannot change review input request input_name")
1733 }
1734 if new.force_execution != existing.force_execution {
1735 unreachable!("cannot change review input request force_execution")
1736 }
1737 Some(new_type.clone())
1738 } else {
1739 None
1740 }
1741 }
1742 ActionItemRequestType::ProvideInput(new) => {
1743 let Some(existing) = existing_item.as_provide_input() else {
1744 unreachable!("cannot change action item request type")
1745 };
1746 if new.default_value != existing.default_value {
1747 if new.input_name != existing.input_name {
1748 unreachable!("cannot change provide input request input_name")
1749 }
1750 if new.typing != existing.typing {
1751 unreachable!("cannot change provide input request typing")
1752 }
1753 Some(new_type.clone())
1754 } else {
1755 None
1756 }
1757 }
1758 ActionItemRequestType::PickInputOption(_) => {
1759 let Some(_) = existing_item.as_pick_input() else {
1760 unreachable!("cannot change action item request type")
1761 };
1762 Some(new_type.clone())
1763 }
1764 ActionItemRequestType::ProvidePublicKey(new) => {
1765 let Some(existing) = existing_item.as_provide_public_key() else {
1766 unreachable!("cannot change action item request type")
1767 };
1768 if new.message != existing.message {
1769 if new.check_expectation_action_uuid != existing.check_expectation_action_uuid {
1770 unreachable!("cannot change provide public key request check_expectation_action_uuid");
1771 }
1772 if new.namespace != existing.namespace {
1773 unreachable!("cannot change provide public key request namespace");
1774 }
1775 if new.network_id != existing.network_id {
1776 unreachable!("cannot change provide public key request network_id");
1777 }
1778 Some(new_type.clone())
1779 } else {
1780 None
1781 }
1782 }
1783 ActionItemRequestType::ProvideSignedTransaction(new) => {
1784 let Some(existing) = existing_item.as_provide_signed_tx() else {
1785 unreachable!("cannot change action item request type")
1786 };
1787 if new.payload != existing.payload || new.skippable != existing.skippable {
1788 if new.check_expectation_action_uuid != existing.check_expectation_action_uuid {
1789 unreachable!(
1790 "cannot change provide signed tx request check_expectation_action_uuid"
1791 );
1792 }
1793 if new.signer_uuid != existing.signer_uuid {
1794 unreachable!("cannot change provide signed tx request signer_uuid");
1795 }
1796 if new.namespace != existing.namespace {
1797 unreachable!("cannot change provide signed tx request namespace");
1798 }
1799 if new.network_id != existing.network_id {
1800 unreachable!("cannot change provide signed tx request network_id");
1801 }
1802 if new.only_approval_needed != existing.only_approval_needed {
1803 unreachable!(
1804 "cannot change provide signed tx request only_approval_needed"
1805 );
1806 }
1807 Some(new_type.clone())
1808 } else {
1809 None
1810 }
1811 }
1812 ActionItemRequestType::VerifyThirdPartySignature(new) => {
1813 let Some(existing) = existing_item.as_verify_third_party_signature() else {
1814 unreachable!("cannot change action item request type")
1815 };
1816 if new.url != existing.url || new.payload != existing.payload {
1817 if new.check_expectation_action_uuid != existing.check_expectation_action_uuid {
1818 unreachable!(
1819 "cannot change verify third party signature request check_expectation_action_uuid"
1820 );
1821 }
1822 if new.signer_uuid != existing.signer_uuid {
1823 unreachable!(
1824 "cannot change verify third party signature request signer_uuid"
1825 );
1826 }
1827 if new.namespace != existing.namespace {
1828 unreachable!(
1829 "cannot change verify third party signature request namespace"
1830 );
1831 }
1832 if new.network_id != existing.network_id {
1833 unreachable!(
1834 "cannot change verify third party signature request network_id"
1835 );
1836 }
1837 Some(new_type.clone())
1838 } else {
1839 None
1840 }
1841 }
1842 ActionItemRequestType::SendTransaction(new) => {
1843 let Some(existing) = existing_item.as_sign_tx() else {
1844 unreachable!("cannot change action item request type")
1845 };
1846 if new.payload != existing.payload {
1847 if new.check_expectation_action_uuid != existing.check_expectation_action_uuid {
1848 unreachable!(
1849 "cannot change provide signed tx request check_expectation_action_uuid"
1850 );
1851 }
1852 if new.signer_uuid != existing.signer_uuid {
1853 unreachable!("cannot change provide signed tx request signer_uuid");
1854 }
1855 if new.namespace != existing.namespace {
1856 unreachable!("cannot change provide signed tx request namespace");
1857 }
1858 if new.network_id != existing.network_id {
1859 unreachable!("cannot change provide signed tx request network_id");
1860 }
1861 Some(new_type.clone())
1862 } else {
1863 None
1864 }
1865 }
1866 ActionItemRequestType::ProvideSignedMessage(new) => {
1867 let Some(existing) = existing_item.as_provide_signed_msg() else {
1868 unreachable!("cannot change action item request type")
1869 };
1870 if new.message != existing.message {
1871 if new.check_expectation_action_uuid != existing.check_expectation_action_uuid {
1872 unreachable!(
1873 "cannot change provide signed msg request check_expectation_action_uuid"
1874 );
1875 }
1876 if new.signer_uuid != existing.signer_uuid {
1877 unreachable!("cannot change provide signed msg request signer_uuid");
1878 }
1879 if new.namespace != existing.namespace {
1880 unreachable!("cannot change provide signed msg request namespace");
1881 }
1882 if new.network_id != existing.network_id {
1883 unreachable!("cannot change provide signed msg request network_id");
1884 }
1885 Some(new_type.clone())
1886 } else {
1887 None
1888 }
1889 }
1890 ActionItemRequestType::DisplayOutput(_) => None,
1891 ActionItemRequestType::DisplayErrorLog(_) => None,
1892 ActionItemRequestType::OpenModal(_) => None,
1893 ActionItemRequestType::ValidateBlock(_) => None,
1894 ActionItemRequestType::ValidateModal => None,
1895 ActionItemRequestType::BeginFlow(_) => None,
1896 }
1897 }
1898}
1899
1900#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1901#[serde(rename_all = "camelCase")]
1902pub struct ReviewInputRequest {
1903 pub input_name: String,
1904 pub value: Value,
1905 pub force_execution: bool,
1906}
1907
1908impl ReviewInputRequest {
1909 pub fn new(input_name: &str, value: &Value) -> Self {
1910 ReviewInputRequest {
1911 input_name: input_name.to_string(),
1912 value: value.clone(),
1913 force_execution: false,
1914 }
1915 }
1916 pub fn force_execution(&mut self) -> &mut Self {
1917 self.force_execution = true;
1918 self
1919 }
1920 pub fn to_action_type(&self) -> ActionItemRequestType {
1921 ActionItemRequestType::ReviewInput(self.clone())
1922 }
1923}
1924
1925#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1926#[serde(rename_all = "camelCase")]
1927pub struct ProvideInputRequest {
1928 pub default_value: Option<Value>,
1929 pub input_name: String,
1930 pub typing: Type,
1931}
1932
1933#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1934#[serde(rename_all = "camelCase")]
1935pub struct DisplayOutputRequest {
1936 pub name: String,
1937 pub description: Option<String>,
1938 pub value: Value,
1939}
1940
1941#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1942#[serde(rename_all = "camelCase")]
1943pub struct DisplayErrorLogRequest {
1944 pub diagnostic: Diagnostic,
1945}
1946
1947#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1948#[serde(rename_all = "camelCase")]
1949pub struct ValidateBlockData {
1950 internal_idx: usize,
1952}
1953impl ValidateBlockData {
1954 pub fn new(internal_idx: usize) -> Self {
1955 ValidateBlockData { internal_idx }
1956 }
1957}
1958
1959#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1960#[serde(rename_all = "camelCase")]
1961pub struct FlowBlockData {
1962 index: usize,
1963 total_flows: usize,
1964 name: String,
1965 description: Option<String>,
1966}
1967
1968#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1969#[serde(rename_all = "camelCase")]
1970pub struct PickInputOptionRequest {
1971 pub options: Vec<InputOption>,
1972 pub selected: InputOption,
1973}
1974#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1975#[serde(rename_all = "camelCase")]
1976pub struct InputOption {
1977 pub value: String,
1978 pub displayed_value: String,
1979}
1980
1981impl InputOption {
1982 pub fn default() -> Self {
1983 InputOption { value: String::new(), displayed_value: String::new() }
1984 }
1985}
1986
1987#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1988#[serde(rename_all = "camelCase")]
1989pub struct ProvidePublicKeyRequest {
1990 pub check_expectation_action_uuid: Option<ConstructDid>,
1991 pub message: String,
1992 pub namespace: String,
1993 pub network_id: String,
1994}
1995
1996#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1997#[serde(rename_all = "camelCase")]
1998pub struct ProvideSignedTransactionRequest {
1999 pub check_expectation_action_uuid: Option<ConstructDid>,
2000 pub signer_uuid: ConstructDid,
2001 pub expected_signer_address: Option<String>,
2002 pub skippable: bool,
2003 pub only_approval_needed: bool,
2004 pub payload: Value,
2005 pub formatted_payload: Option<Value>,
2006 pub namespace: String,
2007 pub network_id: String,
2008}
2009
2010impl ProvideSignedTransactionRequest {
2011 pub fn new(signer_uuid: &Did, payload: &Value, namespace: &str, network_id: &str) -> Self {
2012 ProvideSignedTransactionRequest {
2013 signer_uuid: ConstructDid(signer_uuid.clone()),
2014 check_expectation_action_uuid: None,
2015 expected_signer_address: None,
2016 skippable: false,
2017 payload: payload.clone(),
2018 formatted_payload: None,
2019 namespace: namespace.to_string(),
2020 network_id: network_id.to_string(),
2021 only_approval_needed: false,
2022 }
2023 }
2024
2025 pub fn skippable(&mut self, is_skippable: bool) -> &mut Self {
2026 self.skippable = is_skippable;
2027 self
2028 }
2029
2030 pub fn only_approval_needed(&mut self) -> &mut Self {
2031 self.only_approval_needed = true;
2032 self
2033 }
2034
2035 pub fn check_expectation_action_uuid(&mut self, uuid: &ConstructDid) -> &mut Self {
2036 self.check_expectation_action_uuid = Some(uuid.clone());
2037 self
2038 }
2039
2040 pub fn expected_signer_address(&mut self, address: Option<&str>) -> &mut Self {
2041 self.expected_signer_address = address.and_then(|a| Some(a.to_string()));
2042 self
2043 }
2044
2045 pub fn formatted_payload(&mut self, display_payload: Option<&Value>) -> &mut Self {
2046 self.formatted_payload = display_payload.cloned();
2047 self
2048 }
2049
2050 pub fn to_action_type(&self) -> ActionItemRequestType {
2051 ActionItemRequestType::ProvideSignedTransaction(self.clone())
2052 }
2053}
2054
2055#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2056#[serde(rename_all = "camelCase")]
2057pub struct VerifyThirdPartySignatureRequest {
2058 pub check_expectation_action_uuid: Option<ConstructDid>,
2059 pub signer_uuid: ConstructDid,
2060 pub namespace: String,
2061 pub network_id: String,
2062 pub signer_name: String,
2063 pub third_party_name: String,
2064 pub url: String,
2065 pub payload: Value,
2066 pub formatted_payload: Option<Value>,
2067}
2068
2069impl VerifyThirdPartySignatureRequest {
2070 pub fn new(
2071 signer_uuid: &Did,
2072 url: &str,
2073 signer_name: &str,
2074 third_party_name: &str,
2075 payload: &Value,
2076 namespace: &str,
2077 network_id: &str,
2078 ) -> Self {
2079 VerifyThirdPartySignatureRequest {
2080 signer_uuid: ConstructDid(signer_uuid.clone()),
2081 check_expectation_action_uuid: None,
2082 signer_name: signer_name.to_string(),
2083 third_party_name: third_party_name.to_string(),
2084 url: url.to_string(),
2085 namespace: namespace.to_string(),
2086 network_id: network_id.to_string(),
2087 payload: payload.clone(),
2088 formatted_payload: None,
2089 }
2090 }
2091
2092 pub fn check_expectation_action_uuid(&mut self, uuid: &ConstructDid) -> &mut Self {
2093 self.check_expectation_action_uuid = Some(uuid.clone());
2094 self
2095 }
2096
2097 pub fn formatted_payload(&mut self, display_payload: Option<&Value>) -> &mut Self {
2098 self.formatted_payload = display_payload.cloned();
2099 self
2100 }
2101
2102 pub fn to_action_type(&self) -> ActionItemRequestType {
2103 ActionItemRequestType::VerifyThirdPartySignature(self.clone())
2104 }
2105}
2106
2107#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2108#[serde(rename_all = "camelCase")]
2109pub struct SendTransactionRequest {
2110 pub check_expectation_action_uuid: Option<ConstructDid>,
2111 pub signer_uuid: ConstructDid,
2112 pub expected_signer_address: Option<String>,
2113 pub payload: Value,
2114 pub formatted_payload: Option<Value>,
2115 pub namespace: String,
2116 pub network_id: String,
2117}
2118
2119impl SendTransactionRequest {
2120 pub fn new(signer_uuid: &Did, payload: &Value, namespace: &str, network_id: &str) -> Self {
2121 SendTransactionRequest {
2122 signer_uuid: ConstructDid(signer_uuid.clone()),
2123 check_expectation_action_uuid: None,
2124 expected_signer_address: None,
2125 payload: payload.clone(),
2126 formatted_payload: None,
2127 namespace: namespace.to_string(),
2128 network_id: network_id.to_string(),
2129 }
2130 }
2131
2132 pub fn check_expectation_action_uuid(&mut self, uuid: &ConstructDid) -> &mut Self {
2133 self.check_expectation_action_uuid = Some(uuid.clone());
2134 self
2135 }
2136
2137 pub fn expected_signer_address(&mut self, address: Option<&str>) -> &mut Self {
2138 self.expected_signer_address = address.and_then(|a| Some(a.to_string()));
2139 self
2140 }
2141
2142 pub fn formatted_payload(&mut self, display_payload: Option<&Value>) -> &mut Self {
2143 self.formatted_payload = display_payload.cloned();
2144 self
2145 }
2146
2147 pub fn to_action_type(&self) -> ActionItemRequestType {
2148 ActionItemRequestType::SendTransaction(self.clone())
2149 }
2150}
2151
2152#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2153#[serde(rename_all = "camelCase")]
2154pub struct ProvideSignedMessageRequest {
2155 pub check_expectation_action_uuid: Option<ConstructDid>,
2156 pub signer_uuid: ConstructDid,
2157 pub message: Value,
2158 pub namespace: String,
2159 pub network_id: String,
2160}
2161
2162#[derive(Debug, Clone, Serialize, Deserialize)]
2163#[serde(rename_all = "camelCase")]
2164pub struct ActionItemResponse {
2165 pub action_item_id: BlockId,
2166 #[serde(flatten)]
2167 pub payload: ActionItemResponseType,
2168}
2169
2170#[derive(Debug, Clone, Serialize, Deserialize)]
2171#[serde(tag = "type", content = "data")]
2172pub enum ActionItemResponseType {
2173 ReviewInput(ReviewedInputResponse),
2174 ProvideInput(ProvidedInputResponse),
2175 PickInputOption(String),
2176 ProvidePublicKey(ProvidePublicKeyResponse),
2177 ProvideSignedMessage(ProvideSignedMessageResponse),
2178 ProvideSignedTransaction(ProvideSignedTransactionResponse),
2179 VerifyThirdPartySignature(VerifyThirdPartySignatureResponse),
2180 SendTransaction(SendTransactionResponse),
2181 ValidateBlock,
2182 ValidateModal,
2183}
2184
2185impl ActionItemResponseType {
2186 pub fn is_validate_panel(&self) -> bool {
2187 match &self {
2188 ActionItemResponseType::ValidateBlock => true,
2189 _ => false,
2190 }
2191 }
2192}
2193
2194#[derive(Debug, Clone, Serialize, Deserialize)]
2195#[serde(rename_all = "camelCase")]
2196pub struct ReviewedInputResponse {
2197 pub input_name: String,
2198 pub value_checked: bool,
2199 pub force_execution: bool,
2200}
2201
2202#[derive(Debug, Clone, Serialize, Deserialize)]
2203#[serde(rename_all = "camelCase")]
2204pub struct ProvidedInputResponse {
2205 pub input_name: String,
2206 pub updated_value: Value,
2207}
2208
2209#[derive(Debug, Clone, Serialize, Deserialize)]
2210#[serde(rename_all = "camelCase")]
2211pub struct ProvidePublicKeyResponse {
2212 pub public_key: String,
2213}
2214
2215#[derive(Debug, Clone, Serialize, Deserialize)]
2216#[serde(rename_all = "camelCase")]
2217pub struct ProvideSignedMessageResponse {
2218 pub signed_message_bytes: String,
2219 pub signer_uuid: ConstructDid,
2220}
2221
2222#[derive(Debug, Clone, Serialize, Deserialize)]
2223#[serde(rename_all = "camelCase")]
2224pub struct ProvideSignedTransactionResponse {
2225 pub signed_transaction_bytes: Option<String>,
2226 pub signature_approved: Option<bool>,
2227 pub signer_uuid: ConstructDid,
2228}
2229#[derive(Debug, Clone, Serialize, Deserialize)]
2230#[serde(rename_all = "camelCase")]
2231pub struct VerifyThirdPartySignatureResponse {
2232 pub signer_uuid: ConstructDid,
2233 pub signature_complete: bool,
2234}
2235#[derive(Debug, Clone, Serialize, Deserialize)]
2236#[serde(rename_all = "camelCase")]
2237pub struct SendTransactionResponse {
2238 pub transaction_hash: String,
2239 pub signer_uuid: ConstructDid,
2240}
2241
2242#[derive(Debug, Clone, Serialize, Deserialize)]
2243#[serde(rename_all = "camelCase")]
2244pub struct DiscoveryResponse {
2245 pub needs_credentials: bool,
2246 pub client_type: ClientType,
2247}
2248
2249#[derive(Debug, Clone, Serialize, Deserialize)]
2250pub enum ClientType {
2251 Operator,
2252 Participant,
2253}
2254
2255#[derive(Clone, Debug, Serialize, Deserialize)]
2256#[serde(rename_all = "camelCase")]
2257pub struct SupervisorAddonData {
2258 pub addon_name: String,
2259 pub rpc_api_url: Option<String>,
2260}
2261
2262impl SupervisorAddonData {
2263 pub fn new(addon_name: &str, addon_defaults: &AddonDefaults) -> Self {
2264 let rpc_api_url = addon_defaults.store.get_string("rpc_api_url").map(|s| s.to_string());
2265 Self { addon_name: addon_name.to_string(), rpc_api_url }
2266 }
2267}