Skip to main content

kasl/libs/messages/
types.rs

1//! Message type definitions for the kasl application.
2//!
3//! Defines the central `Message` enum that represents all user-facing messages with type safety and compile-time verification.
4//!
5//! ## Usage
6//!
7//! ```rust
8//! use kasl::libs::messages::types::Message;
9//! use kasl::{msg_info, msg_error, msg_success};
10//!
11//! msg_success!(Message::TaskCreated);
12//! msg_error!(Message::ConfigSaveError);
13//! msg_info!(Message::MonitorStarted {
14//!     pause_threshold: 60,
15//!     poll_interval: 500,
16//!     activity_threshold: 30,
17//! });
18//! ```
19
20/// Comprehensive message enumeration for all user-facing communication.
21#[derive(Debug, Clone)]
22pub enum Message {
23    // === AUTOSTART MESSAGES ===
24    AutostartEnabled,
25    AutostartEnabledUser,
26    AutostartDisabled,
27    AutostartAlreadyDisabled,
28    AutostartEnableFailed(String),
29    AutostartDisableFailed(String),
30    AutostartStatus(String),
31    AutostartRequiresAdmin,
32    AutostartCheckingAlternative,
33
34    // === TASK MESSAGES ===
35    TaskCreated,
36    TaskUpdated,
37    TaskNotFound,
38    TaskUpdateFailed,
39    TasksDeletedCount(usize),
40    TasksNotFoundForDate(String),
41    TasksNotFoundSad,
42    TasksHeader,
43    /// Summary line before unified discovery MultiSelect
44    TasksDiscoverySummary {
45        incomplete: usize,
46        jira: usize,
47        gitlab: usize,
48    },
49    /// Non-selectable separator between incomplete and other items
50    TasksDiscoverySeparator,
51    TasksDiscoverySearchingIncomplete,
52    TasksDiscoveryFetchingExternal,
53    NoTaskIdsProvided,
54    TasksNotFoundForIds(Vec<i32>),
55    TasksToBeDeleted,
56    ConfirmDeleteTask,
57    ConfirmDeleteTasks(usize),
58    ConfirmDeleteAllTodayTasks(usize),
59    ConfirmDeleteAllTodayTasksFinal,
60    NoTasksForToday,
61    TaskNotFoundWithId(i32),
62    CurrentTaskState,
63    TaskEditPreview,
64    ConfirmTaskUpdate,
65    NoChangesDetected,
66    NoTasksSelected,
67    SelectTasksToEdit,
68    EditingTask(String),
69    TaskUpdatedWithName(String),
70    TaskSkippedNoChanges(String),
71    TaskEditingCompleted,
72    PromptTaskNameEdit,
73    PromptTaskCommentEdit,
74    PromptTaskCompletenessEdit,
75    TaskCompletenessRange,
76
77    // === WORKDAY MESSAGES ===
78    WorkdayEnded,
79    /// `end` was asked to close a day that was never opened.
80    WorkdayNeverStarted(String), // date
81    WorkdayNotFoundForDate(String),
82    WorkdayCreateFailed,
83    WorkdayStarting(String),                    // date
84    WorkdayCouldNotFindAfterFinalizing(String), // date
85
86    // === CONFIGURATION MESSAGES ===
87    ConfigSaved,
88    ConfigDeleted,
89    ConfigParseError,
90    ConfigSaveError,
91    ConfigModuleGitLab,
92    ConfigModuleJira,
93    ConfigModuleSiServer,
94    ConfigModuleMonitor,
95    ConfigModuleServer,
96    ConfigModuleProductivity,
97    ConfigModuleTaskDiscovery,
98    ConfigModuleJiraInbox,
99    TaskDiscoveryIgnoreListHeader,
100    TaskDiscoveryIgnoreListEmpty,
101    TaskDiscoveryIgnoreNameAdded(String),
102    TaskDiscoveryIgnoreNameExists(String),
103    TaskDiscoveryIgnoreNamesAdded(usize),
104
105    // === REPORT MESSAGES ===
106    DailyReportSent(String),   // date
107    MonthlyReportSent(String), // date
108    MonthlyReportTriggered,
109    ReportSendFailed(String),        // status
110    MonthlyReportSendFailed(String), // status
111    ReportHeader(String),            // date
112    WorkingHoursForMonth(String),    // month/year
113    ReportPayloadHeading {
114        url: String,
115        date: String,
116    },
117
118    // === EXPORT MESSAGES ===
119    ExportingData(String, String), // data type, format
120    ExportCompleted(String),       // file path
121    ExportingAllData,
122
123    // === TEMPLATE MESSAGES ===
124    TemplateCreated(String),
125    TemplateUpdated(String),
126    TemplateDeleted(String),
127    TemplateNotFound(String),
128    TemplateAlreadyExists(String),
129    TemplateCreateFailed,
130    NoTemplatesFound,
131    TemplateListHeader,
132    SelectTemplateToEdit,
133    SelectTemplateToDelete,
134    ConfirmDeleteTemplate(String),
135    EditingTemplate(String),
136    NoTemplatesMatchingQuery(String),
137    TemplateSearchResults(String),
138    SelectTemplateAction,
139    PromptTemplateName,
140    PromptTemplateTaskName,
141    PromptTemplateComment,
142    PromptTemplateCompleteness,
143    CreatingTaskFromTemplate(String),
144    SelectTemplate,
145    CreateTemplateFirst,
146
147    // === TAG MESSAGES ===
148    TagCreated(String),
149    TagUpdated(String),
150    TagDeleted(String),
151    TagNotFound(String),
152    TagAlreadyExists(String),
153    NoTagsFound,
154    TagListHeader,
155    EditingTag(String),
156    SelectTagAction,
157    SelectTagToEdit,
158    SelectTagToDelete,
159    ConfirmDeleteTag(String),
160    ConfirmDeleteTagWithTasks(String, usize), // tag name, task count
161    PromptTagName,
162    PromptTagColor,
163    NoTasksWithTag(String),
164    TasksWithTag(String),
165    TagsAddedToTask(String),
166
167    // === SHORT INTERVALS MESSAGES ===
168    ShortIntervalsDetected(usize, String), // count, total duration
169    PromptMinWorkInterval,
170
171    // === TIME ADJUSTMENT MESSAGES ===
172    WorkdayUpdateFailed,
173
174    // === PAUSE MESSAGES ===
175    PausesTitle(String),
176
177    // === MONITOR MESSAGES ===
178    MonitorStarted {
179        pause_threshold: u64,
180        poll_interval: u64,
181        activity_threshold: u64,
182    },
183    MonitorExitedNormally,
184    MonitorShuttingDown,
185    MonitorError(String),
186    MonitorTaskPanicked(String),
187    PauseStarted,
188    PauseEnded,
189
190    // === WATCHER/DAEMON MESSAGES ===
191    WatcherStarted(u32), // PID
192    WatcherStopped(u32), // PID
193    WatcherNotRunning,
194    WatcherNotRunningPidNotFound,
195    WatcherStartingForeground,
196    WatcherAlreadyRunning,
197    WatcherAlreadyRunningPid(String),    // PID
198    WatcherStoppingExisting(String),     // PID
199    WatcherFailedToStopExisting(String), // error
200    WatcherReceivedSigterm,
201    WatcherReceivedSigint,
202    WatcherReceivedCtrlC,
203    WatcherCtrlCListenFailed(String), // error
204    WatcherSignalHandlingNotSupported,
205    DaemonModeNotSupported,
206    FailedToGetCurrentExecutable,
207    FailedToCreateSigtermHandler,
208    FailedToCreateSigintHandler,
209
210    // === UPDATE MESSAGES ===
211    UpdateAvailable {
212        app_name: String,
213        latest: String,
214    },
215    UpdateCompleted {
216        app_name: String,
217        version: String,
218    },
219    NoUpdateRequired,
220    UpdateDownloadUrlNotSet,
221    UpdateLatestTagNotFound(String),
222    WatcherStoppingForUpdate,
223    WatcherRestartingAfterUpdate,
224    WatcherStoppingForConfig,
225    WatcherRestartingAfterConfig,
226    WatcherRestarted,
227    WatcherRestartFailed {
228        error: String,
229    },
230    UpdateBinaryNotFoundInArchive,
231
232    // === AUTHENTICATION MESSAGES ===
233    WrongPassword(i32), // attempt count
234
235    // === API MESSAGES ===
236    GitlabFetchFailed(String),  // error message
237    GitlabUserIdFailed(String), // error message
238    JiraFetchFailed(String),    // error message
239    SiServerConfigNotFound,
240    SiServerSessionFailed(String),          // error message
241    SiServerRestDatesFailed(String),        // error message
242    SiServerRestDatesParsingFailed(String), // error message
243
244    // === KASL-SERVER MESSAGES ===
245    KaslServerReached {
246        url: String,
247        version: String,
248    },
249    KaslServerConnected {
250        user_name: String,
251        agent_name: String,
252    },
253    KaslServerConfigured(String),        // url
254    KaslServerDatabaseUnhealthy(String), // what the server reported
255    KaslServerUnreachable(String),       // error message
256    KaslServerTokenRejected(String),     // error message
257    KaslServerUrlNeedsScheme(String),    // the url as entered
258    KaslServerTokenEmpty,
259    KaslServerTokenMissing,
260    KaslServerTokenNotRemoved(String), // error message
261    KaslServerNotConnected,
262    KaslServerDisconnected,
263    KaslServerNoDayToPush(String), // the date, as the user would read it
264    KaslServerDayPushed {
265        date: String,
266        pauses: usize,
267        tasks: usize,
268    },
269    KaslServerTasksDeleted(u64),         // how many the server dropped as no longer held here
270    KaslServerPushRejected(String),      // error message
271    KaslServerPushTokenRejected(String), // error message
272    KaslServerPushRetryable(String),     // error message
273    KaslServerDayQueued(String),         // the date now waiting in the outbox
274    KaslServerQueueEmpty,
275    KaslServerQueueOwed(i64), // how many days are waiting
276    KaslServerQueueEntry {
277        date: String,
278        attempts: i32,
279        last_error: Option<String>,
280    },
281    KaslServerQueueSending(usize), // how many days are about to go
282    KaslServerDayRefused {
283        date: String,
284        reason: String,
285    },
286    KaslServerDayDeferred {
287        date: String,
288        reason: String,
289    },
290    KaslServerFlushSummary {
291        accepted: usize,
292        refused: usize,
293        deferred: usize,
294    },
295    KaslServerBackfillRange {
296        from: String,
297        to: String,
298        days: usize,
299    },
300    KaslServerBackfillNoDays {
301        from: String,
302        to: String,
303    },
304    KaslServerBackfillOrderReversed, // --from is later than --to
305    KaslServerBackfillWholeHistory {
306        from: String,
307        to: String,
308        days: usize,
309    },
310    KaslServerBackfillNothingRecorded, // the database holds no workday at all
311    KaslServerCompatibility {
312        server_version: String,
313        api_version: String,
314    },
315    KaslServerPrivacyHeading(String), // the level, as the server names it
316    KaslServerPrivacySummary(String), // the server's one-sentence summary
317    KaslServerPrivacyStoredHeading,
318    KaslServerPrivacyStored {
319        what: String,
320        detail: String,
321    },
322    KaslServerPrivacyNeverHeading,
323    KaslServerPrivacyBullet(String), // one line of a list the server sent
324    KaslServerPrivacyVisibleHeading,
325    KaslServerPrivacyRetention(String), // the server's retention sentence
326    KaslServerPrivacyOnChange(String),  // what changing the level does
327    KaslServerPrivacyUpdatedAt(String), // when the level was last set
328    KaslServerPrivacySetByAdmin,
329
330    // === DATABASE MESSAGES ===
331    DatabaseOperationFailed {
332        operation: String,
333        error: String,
334    },
335    NoIdSet,
336
337    // === FILE SYSTEM MESSAGES ===
338    FileNotFound,
339    InvalidPidFileContent,
340
341    // === SYSTEM/PATH MESSAGES ===
342    PathConfigured,
343    PathConfigWarning {
344        error: String,
345    },
346    PathRegistryQueryError {
347        status: String,
348    },
349    PathRegistryUpdateError {
350        status: String,
351        stderr: String,
352    },
353    FailedToJoinPaths,
354    FailedToExecuteRegQuery,
355    FailedToParseRegOutput,
356    FailedToGetPathFromReg,
357    FailedToExecuteRegSet,
358    FailedToOpenProcess(u32),      // error code
359    FailedToTerminateProcess(u32), // error code
360    ProcessTerminationNotSupported,
361
362    // === PRODUCTIVITY MESSAGES ===
363    MonthlyProductivity(f64), // percentage
364    LowProductivityWarning {
365        current: f64,
366        threshold: f64,
367    },
368    ProductivityTooLowToSend {
369        current: f64,
370        threshold: f64,
371    },
372    ManualPauseCreated {
373        start_time: String,
374        end_time: String,
375        duration_minutes: u64,
376    },
377    ManualPauseOverlaps {
378        start_time: String,
379        end_time: String,
380    },
381    ManualPauseRemoved(i32),
382    ManualPauseNotFound(i32),
383
384    // === ENCRYPTION/SECRET MESSAGES ===
385
386    // === PROMPTS ===
387    PromptTaskName,
388    TaskNameMergedFromPaste,
389    PromptTaskComment,
390    PromptTaskCompleteness,
391    PromptMinPauseDuration,
392    PromptPauseThreshold,
393    PromptPollInterval,
394    PromptActivityThreshold,
395    PromptMinProductivityThreshold,
396    PromptWorkdayHours,
397    PromptMinWorkdayFraction,
398    PromptServerApiUrl,
399    PromptServerAuthToken,
400    PromptKaslServerUrl,
401    PromptKaslServerToken,
402    PromptSelectModules,
403    PromptSelectTasksToImport,
404    PromptSelectTasksToIgnore,
405    PromptSelectIgnoreNamesToRemove,
406    PromptAddIgnoreName,
407
408    // === GENERAL MESSAGES ===
409    OperationCompleted,
410    OperationCancelled,
411    InvalidInput,
412    PermissionDenied,
413    DeprecatedCommand(&'static str, &'static str), // old name, new name
414
415    // === ERROR LOGGING ===
416    ErrorSendingEvents(String),        // error message
417    ErrorSendingMonthlyReport(String), // error message
418    ErrorInRdevListener(String),       // error message
419    ErrorRequestingRestDates(String),  // error message
420
421    // === SPECIFIC UI MESSAGES ===
422    SelectingTask(String), // task name
423
424    // === JIRA INBOX MESSAGES ===
425    JiraInboxRequiresJiraConfig,
426    JiraInboxEmpty,
427    JiraInboxListHeader,
428    /// A cut or truncated list: how many shown of how many active, and the cuts in words.
429    JiraInboxListSliced {
430        shown: usize,
431        total: usize,
432        what: String,
433    },
434    /// The cuts left nothing; `total` is the whole inbox, so the user knows the list is not empty.
435    JiraInboxNoMatch {
436        total: usize,
437        what: String,
438    },
439    JiraInboxSynced {
440        fetched: usize,
441        new_count: usize,
442        changed: usize,
443        gone: usize,
444    },
445    JiraInboxNewIssues(usize),
446    JiraInboxNotFound(String),
447    JiraInboxPinned(String),
448    JiraInboxUnpinned(String),
449    JiraInboxDismissed(String),
450    /// Key, and when it is due back.
451    JiraInboxSnoozed(String, String),
452    JiraInboxUnsnoozed(String),
453    /// Nothing is awake, but this many are asleep.
454    JiraInboxAllSnoozed(i64),
455    /// How many snoozed issues came back.
456    JiraInboxWoke(usize),
457    /// What a triage run came to.
458    JiraInboxTriaged {
459        taken: usize,
460        snoozed: usize,
461        dismissed: usize,
462        skipped: usize,
463        /// Never asked about, because the run was stopped early.
464        left: usize,
465    },
466    JiraInboxOpened(String),
467    JiraInboxTaken(String),
468
469    /// The issue already became a task: key, then the task's name.
470    JiraInboxAlreadyTaken(String, String),
471
472    /// What the inbox holds, shown under the daily report.
473    JiraInboxSummary {
474        total: i64,
475        fresh: i64,
476        taken: i64,
477    },
478    JiraInboxOpenFailed(String),
479
480    /// A courier was handed an action name that is not one of the three.
481    ToastActionUnknown(String),
482    /// What a toast button came to: the one-line outcome, already worded.
483    ToastActionApplied(String),
484    /// A toast button could not be carried out: key, then why.
485    ToastActionFailed(String, String),
486
487    PromptJiraInboxEnabled,
488    PromptJiraInboxPollInterval,
489    PromptJiraInboxNotify,
490    PromptJiraInboxSortFieldId,
491    PromptJiraInboxSortFieldLabel,
492    PromptJiraInboxExtraFieldId,
493    PromptJiraInboxExtraFieldLabel,
494
495    // === MIGRATION MESSAGES ===
496    MigrationsFound(usize),        // count
497    RunningMigration(u32, String), // version, name
498    MigrationCompleted(u32),       // version
499    MigrationFailed(u32, String),  // version, error
500    AllMigrationsCompleted,
501    DatabaseVersion(u32),
502    DatabaseUpToDate,
503    DatabaseNeedsUpdate,
504    MigrationHistory,
505    NothingToRollback,
506    RollingBack(u32, u32),  // from, to
507    RollbackCompleted(u32), // version
508}