1use chrono::{
2 DateTime,
3 Utc,
4};
5pub use pipedash_plugin_api::{
6 LineMarker,
7 LogAvailability,
8 LogDialect,
9 LogNodeKind,
10 LogSink,
11 ParsedLine,
12 PlainDialect,
13};
14use serde::{
15 Deserialize,
16 Serialize,
17};
18
19use super::pipeline::PipelineStatus;
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct LogNode {
23 pub id: String,
24 pub parent_id: Option<String>,
25 pub kind: LogNodeKind,
26 pub name: String,
27 pub status: PipelineStatus,
28 pub started_at: Option<DateTime<Utc>>,
29 pub finished_at: Option<DateTime<Utc>>,
30 pub log: Option<LogAvailability>,
31 pub web_url: Option<String>,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct RunLogTree {
36 pub nodes: Vec<RunLogNode>,
37 pub default_node_id: Option<String>,
38 pub complete: bool,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct RunLogNode {
43 pub id: String,
44 pub parent_id: Option<String>,
45 pub kind: LogNodeKind,
46 pub name: String,
47 pub status: PipelineStatus,
48 pub started_at: Option<DateTime<Utc>>,
49 pub finished_at: Option<DateTime<Utc>>,
50 pub duration_seconds: Option<i64>,
51 pub log: Option<LogAvailability>,
52 pub web_url: Option<String>,
53 pub depth: u8,
54 pub navigable: bool,
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58#[serde(tag = "state", rename_all = "snake_case")]
59pub enum RunLogDocument {
60 Ready(LogDocumentMeta),
61 Loading { received_bytes: u64 },
62 Pending,
63 Unavailable { message: String },
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct LogDocumentMeta {
68 pub node_id: String,
69 pub revision: i64,
70 pub complete: bool,
71 pub truncated: bool,
72 pub line_count: u32,
73 pub text_bytes: u64,
74 pub first_timestamp_ms: Option<i64>,
75 pub styles: Vec<LogStyle>,
76 pub sections: Vec<LogSection>,
77 pub error_lines: Vec<u32>,
78 pub warning_lines: Vec<u32>,
79 pub error_total: u32,
80 pub warning_total: u32,
81 pub focus_line: Option<u32>,
82}
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
85#[serde(rename_all = "lowercase")]
86pub enum LogSectionKind {
87 Step,
88 Group,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct LogSection {
93 pub id: u32,
94 pub parent: Option<u32>,
95 pub kind: LogSectionKind,
96 pub node_id: Option<String>,
97 pub title: String,
98 pub status: Option<PipelineStatus>,
99 pub duration_ms: Option<i64>,
100 pub header_line: Option<u32>,
101 pub start_line: u32,
102 pub end_line: u32,
103 pub error_count: u32,
104 pub open: bool,
105}
106
107#[derive(Debug, Clone, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
108pub struct LogStyle {
109 pub fg: Option<AnsiColor>,
110 pub bg: Option<AnsiColor>,
111 pub bold: bool,
112 pub dim: bool,
113 pub italic: bool,
114 pub underline: bool,
115 pub strike: bool,
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
119#[serde(rename_all = "lowercase")]
120pub enum AnsiColor {
121 Black,
122 Red,
123 Green,
124 Yellow,
125 Blue,
126 Magenta,
127 Cyan,
128 White,
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
132#[serde(rename_all = "lowercase")]
133#[repr(u8)]
134pub enum LineKind {
135 #[default]
136 Plain = 0,
137 Group = 1,
138 Error = 2,
139 Warning = 3,
140 Notice = 4,
141 Debug = 5,
142 Command = 6,
143}
144
145impl LineKind {
146 pub fn is_plain(&self) -> bool {
147 *self == LineKind::Plain
148 }
149
150 pub fn from_u8(value: u8) -> Option<Self> {
151 Some(match value {
152 0 => LineKind::Plain,
153 1 => LineKind::Group,
154 2 => LineKind::Error,
155 3 => LineKind::Warning,
156 4 => LineKind::Notice,
157 5 => LineKind::Debug,
158 6 => LineKind::Command,
159 _ => return None,
160 })
161 }
162}
163
164#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct LogLinesPage {
166 pub start: u32,
167 pub lines: Vec<LogLine>,
168}
169
170fn is_zero(value: &u32) -> bool {
171 *value == 0
172}
173
174#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
175pub struct LogLine {
176 pub text: String,
177 #[serde(default, skip_serializing_if = "LineKind::is_plain")]
178 pub kind: LineKind,
179 #[serde(default, skip_serializing_if = "Option::is_none")]
180 pub ts: Option<i64>,
181 #[serde(default, skip_serializing_if = "Vec::is_empty")]
182 pub spans: Vec<(u32, u32, u16)>,
183 #[serde(default, skip_serializing_if = "is_zero")]
184 pub omitted: u32,
185}
186
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct LogSearchQuery {
189 pub text: String,
190 pub regex: bool,
191 pub case_sensitive: bool,
192}
193
194#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
195pub struct LogSearchResult {
196 pub matches: Vec<(u32, u32, u32)>,
197 pub total: u64,
198 pub capped: bool,
199}
200
201#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
202pub struct LogCacheStats {
203 pub bytes: u64,
204 pub runs: u64,
205}