From 3b840ada2e1c35d2831df7e49571ad5d8269bd64 Mon Sep 17 00:00:00 2001 From: Kujtim Hoxha Date: Mon, 9 Jun 2025 15:57:07 +0200 Subject: [PATCH] chore: initial logs changes --- internal/config/init.go | 4 +- internal/tui/components/chat/editor/editor.go | 1 - internal/tui/components/core/helpers.go | 26 +-- .../tui/components/dialogs/compact/compact.go | 1 - .../tui/components/dialogs/compact/keys.go | 2 +- internal/tui/components/logs/details.go | 91 +++++++--- internal/tui/components/logs/table.go | 155 +++++++++++++----- internal/tui/page/chat/chat.go | 2 - internal/tui/page/logs/keys.go | 37 +++++ internal/tui/page/{ => logs}/logs.go | 48 ++++-- internal/tui/tui.go | 8 +- todos.md | 9 +- 12 files changed, 270 insertions(+), 114 deletions(-) create mode 100644 internal/tui/page/logs/keys.go rename internal/tui/page/{ => logs}/logs.go (55%) diff --git a/internal/config/init.go b/internal/config/init.go index 1221f348cc69a064e6e95e910127241980e2941c..df9f213f15ddd4e85f912e3c121276a7da28ac09 100644 --- a/internal/config/init.go +++ b/internal/config/init.go @@ -63,13 +63,13 @@ func crushMdExists(dir string) (bool, error) { if entry.IsDir() { continue } - + name := strings.ToLower(entry.Name()) if name == "crush.md" { return true, nil } } - + return false, nil } diff --git a/internal/tui/components/chat/editor/editor.go b/internal/tui/components/chat/editor/editor.go index 0eb63fb9e836de1ff5c45bf7e91a4dcc12309e08..d0b936349db07598a33de8bd48238e16c6cb9524 100644 --- a/internal/tui/components/chat/editor/editor.go +++ b/internal/tui/components/chat/editor/editor.go @@ -360,7 +360,6 @@ func (c *editorCmp) Blur() tea.Cmd { // Focus implements Container. func (c *editorCmp) Focus() tea.Cmd { - logging.Info("Focusing editor textarea") return c.textarea.Focus() } diff --git a/internal/tui/components/core/helpers.go b/internal/tui/components/core/helpers.go index 74a1feef003d878cc8d71db736c0b4969561a3dc..e586b0563278080eb85c7e0bbaa4dbee86e670e9 100644 --- a/internal/tui/components/core/helpers.go +++ b/internal/tui/components/core/helpers.go @@ -78,39 +78,39 @@ func Status(ops StatusOpts, width int) string { } type ButtonOpts struct { - Text string - UnderlineIndex int // Index of character to underline (0-based) - Selected bool // Whether this button is selected + Text string + UnderlineIndex int // Index of character to underline (0-based) + Selected bool // Whether this button is selected } // SelectableButton creates a button with an underlined character and selection state func SelectableButton(opts ButtonOpts) string { t := styles.CurrentTheme() - + // Base style for the button buttonStyle := t.S().Text - + // Apply selection styling if opts.Selected { buttonStyle = buttonStyle.Foreground(t.White).Background(t.Secondary) } else { buttonStyle = buttonStyle.Background(t.BgSubtle) } - + // Create the button text with underlined character text := opts.Text if opts.UnderlineIndex >= 0 && opts.UnderlineIndex < len(text) { before := text[:opts.UnderlineIndex] underlined := text[opts.UnderlineIndex : opts.UnderlineIndex+1] after := text[opts.UnderlineIndex+1:] - - message := buttonStyle.Render(before) + - buttonStyle.Underline(true).Render(underlined) + + + message := buttonStyle.Render(before) + + buttonStyle.Underline(true).Render(underlined) + buttonStyle.Render(after) - + return buttonStyle.Padding(0, 2).Render(message) } - + // Fallback if no underline index specified return buttonStyle.Padding(0, 2).Render(text) } @@ -120,7 +120,7 @@ func SelectableButtons(buttons []ButtonOpts, spacing string) string { if spacing == "" { spacing = " " } - + var parts []string for i, button := range buttons { parts = append(parts, SelectableButton(button)) @@ -128,6 +128,6 @@ func SelectableButtons(buttons []ButtonOpts, spacing string) string { parts = append(parts, spacing) } } - + return lipgloss.JoinHorizontal(lipgloss.Left, parts...) } diff --git a/internal/tui/components/dialogs/compact/compact.go b/internal/tui/components/dialogs/compact/compact.go index afa7c8945009fb7b76d979e466cae290757f3f27..895053279ff916b113051aca3eeb1652ec82936e 100644 --- a/internal/tui/components/dialogs/compact/compact.go +++ b/internal/tui/components/dialogs/compact/compact.go @@ -263,4 +263,3 @@ func (c *compactDialogCmp) Position() (int, int) { func (c *compactDialogCmp) ID() dialogs.DialogID { return CompactDialogID } - diff --git a/internal/tui/components/dialogs/compact/keys.go b/internal/tui/components/dialogs/compact/keys.go index 0f176927a173ec44db9ec85a9f476723f0cb4b94..3d15d3e4caad747fbd2511ce09f5f4ce994236b6 100644 --- a/internal/tui/components/dialogs/compact/keys.go +++ b/internal/tui/components/dialogs/compact/keys.go @@ -58,4 +58,4 @@ func (k KeyMap) ShortHelp() []key.Binding { k.Select, k.Close, } -} \ No newline at end of file +} diff --git a/internal/tui/components/logs/details.go b/internal/tui/components/logs/details.go index 9951b1441bcd3a16c75689e80c25b16f90291cda..82bec5a32fb840624f63cc326672174f2c8b0d4f 100644 --- a/internal/tui/components/logs/details.go +++ b/internal/tui/components/logs/details.go @@ -52,43 +52,55 @@ func (i *detailCmp) updateContent() { var content strings.Builder t := styles.CurrentTheme() - // Format the header with timestamp and level - timeStyle := t.S().Muted + if i.currentLog.ID == "" { + content.WriteString(t.S().Muted.Render("No log selected")) + i.viewport.SetContent(content.String()) + return + } + + // Level badge with background color levelStyle := getLevelStyle(i.currentLog.Level) + levelBadge := levelStyle.Padding(0, 1).Render(strings.ToUpper(i.currentLog.Level)) + // Timestamp with relative time + timeStr := i.currentLog.Time.Format("2006-01-05 15:04:05 UTC") + relativeTime := getRelativeTime(i.currentLog.Time) + timeStyle := t.S().Muted + + // Header line header := lipgloss.JoinHorizontal( - lipgloss.Center, - timeStyle.Render(i.currentLog.Time.Format(time.RFC3339)), - " ", - levelStyle.Render(i.currentLog.Level), + lipgloss.Left, + timeStr, + " ", + timeStyle.Render(relativeTime), ) - content.WriteString(lipgloss.NewStyle().Bold(true).Render(header)) + content.WriteString(levelBadge) + content.WriteString("\n\n") + content.WriteString(header) content.WriteString("\n\n") - // Message with styling - messageStyle := t.S().Text.Bold(true) - content.WriteString(messageStyle.Render("Message:")) + // Message section + messageHeaderStyle := t.S().Base.Foreground(t.Blue).Bold(true) + content.WriteString(messageHeaderStyle.Render("Message")) content.WriteString("\n") - content.WriteString(lipgloss.NewStyle().Padding(0, 2).Render(i.currentLog.Message)) + content.WriteString(i.currentLog.Message) content.WriteString("\n\n") // Attributes section if len(i.currentLog.Attributes) > 0 { - attrHeaderStyle := t.S().Text.Bold(true) - content.WriteString(attrHeaderStyle.Render("Attributes:")) + attrHeaderStyle := t.S().Base.Foreground(t.Blue).Bold(true) + content.WriteString(attrHeaderStyle.Render("Attributes")) content.WriteString("\n") - // Create a table-like display for attributes - keyStyle := t.S().Base.Foreground(t.Primary).Bold(true) - valueStyle := t.S().Text - for _, attr := range i.currentLog.Attributes { + keyStyle := t.S().Base.Foreground(t.Accent) + valueStyle := t.S().Text attrLine := fmt.Sprintf("%s: %s", keyStyle.Render(attr.Key), valueStyle.Render(attr.Value), ) - content.WriteString(lipgloss.NewStyle().Padding(0, 2).Render(attrLine)) + content.WriteString(attrLine) content.WriteString("\n") } } @@ -102,20 +114,48 @@ func getLevelStyle(level string) lipgloss.Style { switch strings.ToLower(level) { case "info": - return style.Foreground(t.Info) + return style.Foreground(t.White).Background(t.Info) case "warn", "warning": - return style.Foreground(t.Warning) + return style.Foreground(t.White).Background(t.Warning) case "error", "err": - return style.Foreground(t.Error) + return style.Foreground(t.White).Background(t.Error) case "debug": - return style.Foreground(t.Success) + return style.Foreground(t.White).Background(t.Success) + case "fatal": + return style.Foreground(t.White).Background(t.Error) default: return style.Foreground(t.FgBase) } } +func getRelativeTime(logTime time.Time) string { + now := time.Now() + diff := now.Sub(logTime) + + if diff < time.Minute { + return fmt.Sprintf("%ds ago", int(diff.Seconds())) + } else if diff < time.Hour { + return fmt.Sprintf("%dm ago", int(diff.Minutes())) + } else if diff < 24*time.Hour { + return fmt.Sprintf("%dh ago", int(diff.Hours())) + } else if diff < 30*24*time.Hour { + return fmt.Sprintf("%dd ago", int(diff.Hours()/24)) + } else if diff < 365*24*time.Hour { + return fmt.Sprintf("%dmo ago", int(diff.Hours()/(24*30))) + } else { + return fmt.Sprintf("%dy ago", int(diff.Hours()/(24*365))) + } +} + func (i *detailCmp) View() tea.View { - return tea.NewView(i.viewport.View()) + t := styles.CurrentTheme() + style := t.S().Base. + BorderStyle(lipgloss.RoundedBorder()). + BorderForeground(t.BorderFocus). + Width(i.width - 2). // Adjust width for border + Height(i.height - 2). // Adjust height for border + Padding(1) + return tea.NewView(style.Render(i.viewport.View())) } func (i *detailCmp) GetSize() (int, int) { @@ -123,10 +163,11 @@ func (i *detailCmp) GetSize() (int, int) { } func (i *detailCmp) SetSize(width int, height int) tea.Cmd { + logging.Info("Setting size for detail component", "width", width, "height", height) i.width = width i.height = height - i.viewport.SetWidth(i.width) - i.viewport.SetHeight(i.height) + i.viewport.SetWidth(i.width - 4) + i.viewport.SetHeight(i.height - 4) i.updateContent() return nil } diff --git a/internal/tui/components/logs/table.go b/internal/tui/components/logs/table.go index fa2cd9dd7d9d42afe31b18215edc48a386655051..d7671ba84304e971134472a78576605454a214c4 100644 --- a/internal/tui/components/logs/table.go +++ b/internal/tui/components/logs/table.go @@ -1,8 +1,9 @@ package logs import ( - "encoding/json" + "fmt" "slices" + "strings" "github.com/charmbracelet/bubbles/v2/key" "github.com/charmbracelet/bubbles/v2/table" @@ -12,6 +13,7 @@ import ( "github.com/charmbracelet/crush/internal/tui/layout" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" + "github.com/charmbracelet/lipgloss/v2" ) type TableComponent interface { @@ -22,48 +24,80 @@ type TableComponent interface { type tableCmp struct { table table.Model + logs []logging.LogMessage } type selectedLogMsg logging.LogMessage func (i *tableCmp) Init() tea.Cmd { + i.logs = logging.List() i.setRows() return nil } func (i *tableCmp) Update(msg tea.Msg) (tea.Model, tea.Cmd) { var cmds []tea.Cmd - switch msg.(type) { + switch msg := msg.(type) { case pubsub.Event[logging.LogMessage]: - i.setRows() - return i, nil + return i, func() tea.Msg { + if msg.Type == pubsub.CreatedEvent { + rows := i.table.Rows() + for _, row := range rows { + if row[1] == msg.Payload.ID { + return nil // If the log already exists, do not add it again + } + } + i.logs = append(i.logs, msg.Payload) + i.table.SetRows( + append( + []table.Row{ + logToRow(msg.Payload), + }, + i.table.Rows()..., + ), + ) + } + return selectedLogMsg(msg.Payload) + } } - prevSelectedRow := i.table.SelectedRow() t, cmd := i.table.Update(msg) cmds = append(cmds, cmd) i.table = t - selectedRow := i.table.SelectedRow() - if selectedRow != nil { - if prevSelectedRow == nil || selectedRow[0] == prevSelectedRow[0] { - var log logging.LogMessage - for _, row := range logging.List() { - if row.ID == selectedRow[0] { - log = row - break - } - } - if log.ID != "" { - cmds = append(cmds, util.CmdHandler(selectedLogMsg(log))) + + cmds = append(cmds, func() tea.Msg { + for _, log := range logging.List() { + if log.ID == i.table.SelectedRow()[1] { + // If the selected row matches the log ID, return the selected log message + return selectedLogMsg(log) } } - } + return nil + }) return i, tea.Batch(cmds...) } func (i *tableCmp) View() tea.View { t := styles.CurrentTheme() defaultStyles := table.DefaultStyles() - defaultStyles.Selected = defaultStyles.Selected.Foreground(t.Primary) + + // Header styling + defaultStyles.Header = defaultStyles.Header. + Foreground(t.Primary). + Bold(true). + BorderStyle(lipgloss.NormalBorder()). + BorderBottom(true). + BorderForeground(t.Border) + + // Selected row styling + defaultStyles.Selected = defaultStyles.Selected. + Foreground(t.FgSelected). + Background(t.Primary). + Bold(false) + + // Cell styling + defaultStyles.Cell = defaultStyles.Cell. + Foreground(t.FgBase) + i.table.SetStyles(defaultStyles) return tea.NewView(i.table.View()) } @@ -75,12 +109,30 @@ func (i *tableCmp) GetSize() (int, int) { func (i *tableCmp) SetSize(width int, height int) tea.Cmd { i.table.SetWidth(width) i.table.SetHeight(height) - cloumns := i.table.Columns() - for i, col := range cloumns { - col.Width = (width / len(cloumns)) - 2 - cloumns[i] = col - } - i.table.SetColumns(cloumns) + + columnWidth := (width - 10) / 4 + i.table.SetColumns([]table.Column{ + { + Title: "Level", + Width: 10, + }, + { + Title: "ID", + Width: columnWidth, + }, + { + Title: "Time", + Width: columnWidth, + }, + { + Title: "Message", + Width: columnWidth, + }, + { + Title: "Attributes", + Width: columnWidth, + }, + }) return nil } @@ -91,39 +143,54 @@ func (i *tableCmp) BindingKeys() []key.Binding { func (i *tableCmp) setRows() { rows := []table.Row{} - logs := logging.List() - slices.SortFunc(logs, func(a, b logging.LogMessage) int { + slices.SortFunc(i.logs, func(a, b logging.LogMessage) int { if a.Time.Before(b.Time) { - return 1 + return -1 } if a.Time.After(b.Time) { - return -1 + return 1 } return 0 }) - for _, log := range logs { - bm, _ := json.Marshal(log.Attributes) + for _, log := range i.logs { + rows = append(rows, logToRow(log)) + } + i.table.SetRows(rows) +} - row := table.Row{ - log.ID, - log.Time.Format("15:04:05"), - log.Level, - log.Message, - string(bm), +func logToRow(log logging.LogMessage) table.Row { + // Format attributes as JSON string + var attrStr string + if len(log.Attributes) > 0 { + var parts []string + for _, attr := range log.Attributes { + parts = append(parts, fmt.Sprintf(`{"Key":"%s","Value":"%s"}`, attr.Key, attr.Value)) } - rows = append(rows, row) + attrStr = "[" + strings.Join(parts, ",") + "]" + } + + // Format time with relative time + timeStr := log.Time.Format("2006-01-05 15:04:05 UTC") + relativeTime := getRelativeTime(log.Time) + fullTimeStr := timeStr + " " + relativeTime + + return table.Row{ + strings.ToUpper(log.Level), + log.ID, + fullTimeStr, + log.Message, + attrStr, } - i.table.SetRows(rows) } func NewLogsTable() TableComponent { columns := []table.Column{ - {Title: "ID", Width: 4}, - {Title: "Time", Width: 4}, - {Title: "Level", Width: 10}, - {Title: "Message", Width: 10}, - {Title: "Attributes", Width: 10}, + {Title: "Level"}, + {Title: "ID"}, + {Title: "Time"}, + {Title: "Message"}, + {Title: "Attributes"}, } tableModel := table.New( diff --git a/internal/tui/page/chat/chat.go b/internal/tui/page/chat/chat.go index 4a501f658e9f5f2b0a1367b11d34c6304c983a48..6ca1ac1e91d42b0896cfa3f8dc0b723ca53b4063 100644 --- a/internal/tui/page/chat/chat.go +++ b/internal/tui/page/chat/chat.go @@ -8,7 +8,6 @@ import ( "github.com/charmbracelet/crush/internal/app" "github.com/charmbracelet/crush/internal/config" "github.com/charmbracelet/crush/internal/llm/models" - "github.com/charmbracelet/crush/internal/logging" "github.com/charmbracelet/crush/internal/message" "github.com/charmbracelet/crush/internal/session" "github.com/charmbracelet/crush/internal/tui/components/chat" @@ -99,7 +98,6 @@ func (p *chatPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return p, util.ReportWarn("File attachments are not supported by the current model: " + string(selectedModelID)) } case key.Matches(msg, p.keyMap.Tab): - logging.Info("Tab key pressed, toggling chat focus") if p.session.ID == "" { return p, nil } diff --git a/internal/tui/page/logs/keys.go b/internal/tui/page/logs/keys.go new file mode 100644 index 0000000000000000000000000000000000000000..e80b3183644142cc6044fc7f45698ee5b01fccb2 --- /dev/null +++ b/internal/tui/page/logs/keys.go @@ -0,0 +1,37 @@ +package logs + +import ( + "github.com/charmbracelet/bubbles/v2/key" + "github.com/charmbracelet/crush/internal/tui/layout" +) + +type KeyMap struct { + Back key.Binding +} + +func DefaultKeyMap() KeyMap { + return KeyMap{ + Back: key.NewBinding( + key.WithKeys("esc", "backspace"), + key.WithHelp("esc/backspace", "back to chat"), + ), + } +} + +// FullHelp implements help.KeyMap. +func (k KeyMap) FullHelp() [][]key.Binding { + m := [][]key.Binding{} + slice := layout.KeyMapToSlice(k) + for i := 0; i < len(slice); i += 4 { + end := min(i+4, len(slice)) + m = append(m, slice[i:end]) + } + return m +} + +// ShortHelp implements help.KeyMap. +func (k KeyMap) ShortHelp() []key.Binding { + return []key.Binding{ + k.Back, + } +} diff --git a/internal/tui/page/logs.go b/internal/tui/page/logs/logs.go similarity index 55% rename from internal/tui/page/logs.go rename to internal/tui/page/logs/logs.go index b66df829713e9aa5f72bd4797f36267e8cc23e7a..5b86fb325beed3d33e866ec6d268610d3f58016c 100644 --- a/internal/tui/page/logs.go +++ b/internal/tui/page/logs/logs.go @@ -1,26 +1,30 @@ -package page +package logs import ( "github.com/charmbracelet/bubbles/v2/key" tea "github.com/charmbracelet/bubbletea/v2" - "github.com/charmbracelet/crush/internal/tui/components/logs" + "github.com/charmbracelet/crush/internal/tui/components/core" + logsComponents "github.com/charmbracelet/crush/internal/tui/components/logs" "github.com/charmbracelet/crush/internal/tui/layout" + "github.com/charmbracelet/crush/internal/tui/page" + "github.com/charmbracelet/crush/internal/tui/page/chat" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" ) -var LogsPage PageID = "logs" +var LogsPage page.PageID = "logs" type LogPage interface { util.Model layout.Sizeable - layout.Bindings } + type logsPage struct { width, height int - table layout.Container - details layout.Container + table logsComponents.TableComponent + details logsComponents.DetailComponent + keyMap KeyMap } func (p *logsPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { @@ -30,34 +34,39 @@ func (p *logsPage) Update(msg tea.Msg) (tea.Model, tea.Cmd) { p.width = msg.Width p.height = msg.Height return p, p.SetSize(msg.Width, msg.Height) + case tea.KeyMsg: + switch { + case key.Matches(msg, p.keyMap.Back): + return p, util.CmdHandler(page.PageChangeMsg{ID: chat.ChatPage}) + } } table, cmd := p.table.Update(msg) cmds = append(cmds, cmd) - p.table = table.(layout.Container) + p.table = table.(logsComponents.TableComponent) details, cmd := p.details.Update(msg) cmds = append(cmds, cmd) - p.details = details.(layout.Container) + p.details = details.(logsComponents.DetailComponent) return p, tea.Batch(cmds...) } func (p *logsPage) View() tea.View { - style := styles.CurrentTheme().S().Base.Width(p.width).Height(p.height) + baseStyle := styles.CurrentTheme().S().Base + style := baseStyle.Width(p.width).Height(p.height).Padding(1) + title := core.Title("Logs", p.width-2) + return tea.NewView( style.Render( lipgloss.JoinVertical(lipgloss.Top, - p.table.View().String(), + title, p.details.View().String(), + p.table.View().String(), ), ), ) } -func (p *logsPage) BindingKeys() []key.Binding { - return p.table.BindingKeys() -} - // GetSize implements LogPage. func (p *logsPage) GetSize() (int, int) { return p.width, p.height @@ -67,9 +76,11 @@ func (p *logsPage) GetSize() (int, int) { func (p *logsPage) SetSize(width int, height int) tea.Cmd { p.width = width p.height = height + availableHeight := height - 2 // Padding for top and bottom + availableHeight -= 1 // title height return tea.Batch( - p.table.SetSize(width, height/2), - p.details.SetSize(width, height/2), + p.table.SetSize(width-2, availableHeight/2), + p.details.SetSize(width-2, availableHeight/2), ) } @@ -82,7 +93,8 @@ func (p *logsPage) Init() tea.Cmd { func NewLogsPage() LogPage { return &logsPage{ - table: layout.NewContainer(logs.NewLogsTable(), layout.WithBorderAll()), - details: layout.NewContainer(logs.NewLogsDetails(), layout.WithBorderAll()), + details: logsComponents.NewLogsDetails(), + table: logsComponents.NewLogsTable(), + keyMap: DefaultKeyMap(), } } diff --git a/internal/tui/tui.go b/internal/tui/tui.go index c14d93bd392c8dd44496efc1a42a8e0d905bb7f6..e2c037a586aaad777412372b79b5596f22d569f4 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -27,6 +27,7 @@ import ( "github.com/charmbracelet/crush/internal/tui/layout" "github.com/charmbracelet/crush/internal/tui/page" "github.com/charmbracelet/crush/internal/tui/page/chat" + "github.com/charmbracelet/crush/internal/tui/page/logs" "github.com/charmbracelet/crush/internal/tui/styles" "github.com/charmbracelet/crush/internal/tui/util" "github.com/charmbracelet/lipgloss/v2" @@ -137,7 +138,7 @@ func (a *appModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { cmds = append(cmds, statusCmd) // If the current page is logs, update the logs view - if a.currentPage == page.LogsPage { + if a.currentPage == logs.LogsPage { updated, pageCmd := a.pages[a.currentPage].Update(msg) a.pages[a.currentPage] = updated.(util.Model) cmds = append(cmds, pageCmd) @@ -328,7 +329,7 @@ func (a *appModel) handleKeyPressMsg(msg tea.KeyPressMsg) tea.Cmd { return tea.Sequence(cmds...) // Page navigation case key.Matches(msg, a.keyMap.Logs): - return a.moveToPage(page.LogsPage) + return a.moveToPage(logs.LogsPage) default: if a.dialog.HasDialogs() { @@ -379,7 +380,6 @@ func (a *appModel) View() tea.View { lipgloss.NewLayer(appView), } if a.dialog.HasDialogs() { - logging.Info("Rendering dialogs") layers = append( layers, a.dialog.GetLayers()..., @@ -424,7 +424,7 @@ func New(app *app.App) tea.Model { pages: map[page.PageID]util.Model{ chat.ChatPage: chat.NewChatPage(app), - page.LogsPage: page.NewLogsPage(), + logs.LogsPage: logs.NewLogsPage(), }, dialog: dialogs.NewDialogCmp(), diff --git a/todos.md b/todos.md index b6c3853b6f44c70bf20851efba3496c09c1c641f..0397c1088aae74a99a4ccf1e2ec4bc12c3be0477 100644 --- a/todos.md +++ b/todos.md @@ -11,9 +11,9 @@ - [x] Cleanup Commands - [x] Sessions dialog -- [ ] Models -- [~] Move sessions and model dialog to the commands -- [ ] Add sessions shortuct +- [x] Models +- [x] Move sessions and model dialog to the commands +- [x] Add sessions shortuct - [ ] Add all posible actions to the commands ## Investigate @@ -24,3 +24,6 @@ ## Messages - [ ] Fix issue with numbers (padding) +- [ ] Run tools in parallel and add the responses in parallel +- [ ] Handle parallel permission calls +- [ ] Weird behavior sometimes the message does not update