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    // === PULSE MESSAGES ===
331    PulseOff,
332    PulseNothingYet,
333    PulseLastSent {
334        ago: String,
335        state: Option<String>,
336    },
337    PulseFailing {
338        ago: String,
339        error: String,
340    },
341    PulseLastArrived(String),  // how long ago the last accepted pulse went
342    PulseSilent(String),       // how long ago the watcher was due to try again
343    PulseShownOffline(String), // how long the server believes a pulse
344    PulseClockSkew(i64),       // seconds, positive when this machine is ahead
345    PulseEnabled(String),      // the server url
346    PulseNoWatcher,
347    PulseFirstArrived(String), // the state the server recorded
348    PulseFirstFailed(String),  // why the first pulse did not arrive
349    PulseFirstPending,
350    PulseDisabled(Option<String>), // how long the server believes a pulse, when known
351    PulseAlreadyOff,
352
353    // === DATABASE MESSAGES ===
354    DatabaseOperationFailed {
355        operation: String,
356        error: String,
357    },
358    NoIdSet,
359
360    // === FILE SYSTEM MESSAGES ===
361    FileNotFound,
362    InvalidPidFileContent,
363
364    // === SYSTEM/PATH MESSAGES ===
365    PathConfigured,
366    PathConfigWarning {
367        error: String,
368    },
369    PathRegistryQueryError {
370        status: String,
371    },
372    PathRegistryUpdateError {
373        status: String,
374        stderr: String,
375    },
376    FailedToJoinPaths,
377    FailedToExecuteRegQuery,
378    FailedToParseRegOutput,
379    FailedToGetPathFromReg,
380    FailedToExecuteRegSet,
381    FailedToOpenProcess(u32),      // error code
382    FailedToTerminateProcess(u32), // error code
383    ProcessTerminationNotSupported,
384
385    // === PRODUCTIVITY MESSAGES ===
386    MonthlyProductivity(f64), // percentage
387    LowProductivityWarning {
388        current: f64,
389        threshold: f64,
390    },
391    ProductivityTooLowToSend {
392        current: f64,
393        threshold: f64,
394    },
395    ManualPauseCreated {
396        start_time: String,
397        end_time: String,
398        duration_minutes: u64,
399    },
400    ManualPauseOverlaps {
401        start_time: String,
402        end_time: String,
403    },
404    ManualPauseRemoved(i32),
405    ManualPauseNotFound(i32),
406
407    // === ENCRYPTION/SECRET MESSAGES ===
408
409    // === PROMPTS ===
410    PromptTaskName,
411    TaskNameMergedFromPaste,
412    PromptTaskComment,
413    PromptTaskCompleteness,
414    PromptMinPauseDuration,
415    PromptPauseThreshold,
416    PromptPollInterval,
417    PromptActivityThreshold,
418    PromptMinProductivityThreshold,
419    PromptWorkdayHours,
420    PromptMinWorkdayFraction,
421    PromptServerApiUrl,
422    PromptServerAuthToken,
423    PromptKaslServerUrl,
424    PromptKaslServerToken,
425    PromptSelectModules,
426    PromptSelectTasksToImport,
427    PromptSelectTasksToIgnore,
428    PromptSelectIgnoreNamesToRemove,
429    PromptAddIgnoreName,
430
431    // === GENERAL MESSAGES ===
432    OperationCompleted,
433    OperationCancelled,
434    InvalidInput,
435    PermissionDenied,
436    DeprecatedCommand(&'static str, &'static str), // old name, new name
437
438    // === ERROR LOGGING ===
439    ErrorSendingEvents(String),        // error message
440    ErrorSendingMonthlyReport(String), // error message
441    ErrorInRdevListener(String),       // error message
442    ErrorRequestingRestDates(String),  // error message
443
444    // === SPECIFIC UI MESSAGES ===
445    SelectingTask(String), // task name
446
447    // === JIRA INBOX MESSAGES ===
448    JiraInboxRequiresJiraConfig,
449    JiraInboxEmpty,
450    JiraInboxListHeader,
451    /// A cut or truncated list: how many shown of how many active, and the cuts in words.
452    JiraInboxListSliced {
453        shown: usize,
454        total: usize,
455        what: String,
456    },
457    /// The cuts left nothing; `total` is the whole inbox, so the user knows the list is not empty.
458    JiraInboxNoMatch {
459        total: usize,
460        what: String,
461    },
462    JiraInboxSynced {
463        fetched: usize,
464        new_count: usize,
465        changed: usize,
466        gone: usize,
467    },
468    JiraInboxNewIssues(usize),
469    JiraInboxNotFound(String),
470    JiraInboxPinned(String),
471    JiraInboxUnpinned(String),
472    JiraInboxDismissed(String),
473    JiraInboxUndismissed(String),
474    /// Key, and when it is due back.
475    JiraInboxSnoozed(String, String),
476    JiraInboxUnsnoozed(String),
477    /// Nothing is awake, but this many are asleep.
478    JiraInboxAllSnoozed(i64),
479    /// How many snoozed issues came back.
480    JiraInboxWoke(usize),
481    /// What a triage run came to.
482    JiraInboxTriaged {
483        taken: usize,
484        snoozed: usize,
485        dismissed: usize,
486        skipped: usize,
487        /// Never asked about, because the run was stopped early.
488        left: usize,
489    },
490    JiraInboxOpened(String),
491    JiraInboxTaken(String),
492
493    /// The issue already became a task: key, then the task's name.
494    JiraInboxAlreadyTaken(String, String),
495
496    /// What the inbox holds, shown under the daily report.
497    JiraInboxSummary {
498        total: i64,
499        fresh: i64,
500        taken: i64,
501    },
502    JiraInboxOpenFailed(String),
503
504    /// How many inbox rules could not be read and are skipped.
505    InboxRulesSkipped(usize),
506    /// One skipped rule: its number in the config, then why.
507    InboxRuleSkipped(usize, String),
508    /// What the rules did to one issue, already worded.
509    InboxRuleActed(String),
510    /// The config holds no inbox rules.
511    InboxRulesNone,
512    /// `rules --apply` finished: how many issues it changed.
513    InboxRulesApplied(usize),
514    /// Issues a rule matches that its pin or dismissal has not reached.
515    InboxRulesNotApplied(usize),
516
517    /// A courier was handed an action name that is not one of the three.
518    ToastActionUnknown(String),
519    /// What a toast button came to: the one-line outcome, already worded.
520    ToastActionApplied(String),
521    /// A toast button could not be carried out: key, then why.
522    ToastActionFailed(String, String),
523
524    /// What a move in Jira came to, already worded.
525    JiraMoved(String),
526    /// A comment landed on the issue.
527    JiraCommented(String),
528    /// The local change stands, but Jira was not updated: key, then why.
529    JiraWriteFailed(String, String),
530    /// A taken issue was resolved in Jira while its task is open: key, then
531    /// the resolution in parentheses or nothing.
532    JiraResolvedTaskOpen(String, String),
533    /// The question after a linked task reaches 100%.
534    PromptJiraAfterDone(String),
535    PromptJiraCloseComment,
536    PromptJiraComment,
537    PromptMarkResolvedDone,
538
539    PromptJiraInboxEnabled,
540    PromptJiraInboxPollInterval,
541    PromptJiraInboxNotify,
542    PromptJiraInboxSortFieldId,
543    PromptJiraInboxSortFieldLabel,
544    PromptJiraInboxExtraFieldId,
545    PromptJiraInboxExtraFieldLabel,
546
547    // === MIGRATION MESSAGES ===
548    MigrationsFound(usize),        // count
549    RunningMigration(u32, String), // version, name
550    MigrationCompleted(u32),       // version
551    MigrationFailed(u32, String),  // version, error
552    AllMigrationsCompleted,
553    DatabaseVersion(u32),
554    DatabaseUpToDate,
555    DatabaseNeedsUpdate,
556    MigrationHistory,
557    NothingToRollback,
558    RollingBack(u32, u32),  // from, to
559    RollbackCompleted(u32), // version
560}