fix: AcceptSuggestionWith uses flat fields to avoid Wails marshalling issues; human-readable event labels
- AcceptSuggestionWith now accepts nodeID, summary, minutes, date, eventIDs as separate args instead of the entire Suggestion struct (Wails v2 skips nested struct fields during JS→Go marshalling) - Error handling: event link failures now return an error instead of silent ignore - Event type labels in suggestion detail and journal row detail now use eventLabel() which maps snake_case types to human-readable i18n labels (e.g. note_updated → 'Заметка изменена') - Added missing event labels: note_deleted, node_deleted, folder_moved, action_created, action_done, worklog_added
This commit is contained in:
parent
fd99dd4f5c
commit
7076980954
|
|
@ -111,26 +111,29 @@ func (a *App) GetSuggestions() ([]activity.Suggestion, error) {
|
||||||
return suggestions, nil
|
return suggestions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcceptSuggestion creates a worklog entry from a suggestion (compatibility wrapper).
|
// AcceptSuggestion creates a worklog entry from a suggestion (compatibility wrapper, uses flat fields).
|
||||||
func (a *App) AcceptSuggestion(s activity.Suggestion) (*WorklogDTO, error) {
|
func (a *App) AcceptSuggestion(nodeID, summary string, minutes int, date string, eventIDs []string) (*WorklogDTO, error) {
|
||||||
return a.AcceptSuggestionWith(s, s.SuggestedMin, "")
|
return a.AcceptSuggestionWith(nodeID, summary, minutes, date, eventIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcceptSuggestionWith creates a worklog entry with optional overrides.
|
// AcceptSuggestionWith creates a worklog entry and links events. Uses flat fields to avoid Wails marshalling issues.
|
||||||
func (a *App) AcceptSuggestionWith(s activity.Suggestion, minutes int, date string) (*WorklogDTO, error) {
|
func (a *App) AcceptSuggestionWith(nodeID, summary string, minutes int, date string, eventIDs []string) (*WorklogDTO, error) {
|
||||||
d := date
|
d := date
|
||||||
if d == "" {
|
if d == "" {
|
||||||
d = time.Now().Format("2006-01-02")
|
d = time.Now().Format("2006-01-02")
|
||||||
}
|
}
|
||||||
entry, err := a.worklog.AddWithSource(s.NodeID, s.Summary, "", d, minutes, true, false, worklog.SourceSuggestion)
|
entry, err := a.worklog.AddWithSource(nodeID, summary, "", d, minutes, true, false, worklog.SourceSuggestion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Link activity events to this worklog entry.
|
// Link activity events to this worklog entry.
|
||||||
for _, eid := range s.EventIDs {
|
for _, eid := range eventIDs {
|
||||||
_, _ = a.db.Exec(
|
_, err := a.db.Exec(
|
||||||
`INSERT OR IGNORE INTO worklog_entry_events (entry_id, event_id) VALUES (?,?)`,
|
`INSERT OR IGNORE INTO worklog_entry_events (entry_id, event_id) VALUES (?,?)`,
|
||||||
entry.ID, eid)
|
entry.ID, eid)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("link event %s: %w", eid, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ = a.sync.RecordOp(syncsvc.EntityWorklog, entry.ID, syncsvc.OpCreate, worklogPayload(entry))
|
_ = a.sync.RecordOp(syncsvc.EntityWorklog, entry.ID, syncsvc.OpCreate, worklogPayload(entry))
|
||||||
mins := 0
|
mins := 0
|
||||||
|
|
|
||||||
|
|
@ -972,14 +972,14 @@
|
||||||
|
|
||||||
async function acceptTodaySuggestion(s) {
|
async function acceptTodaySuggestion(s) {
|
||||||
try {
|
try {
|
||||||
await wailsCall('AcceptSuggestionWith', s, s.suggestedMin, '')
|
await wailsCall('AcceptSuggestionWith', s.nodeId, s.summary, s.suggestedMin, '', s.eventIds || [])
|
||||||
await refreshAfterSuggestion()
|
await refreshAfterSuggestion()
|
||||||
} catch (e) { console.error(e) }
|
} catch (e) { console.error(e) }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function acceptJournalSuggestion(s) {
|
async function acceptJournalSuggestion(s) {
|
||||||
try {
|
try {
|
||||||
await wailsCall('AcceptSuggestionWith', s, s.suggestedMin, '')
|
await wailsCall('AcceptSuggestionWith', s.nodeId, s.summary, s.suggestedMin, '', s.eventIds || [])
|
||||||
await refreshAfterSuggestion()
|
await refreshAfterSuggestion()
|
||||||
} catch (e) { console.error(e) }
|
} catch (e) { console.error(e) }
|
||||||
}
|
}
|
||||||
|
|
@ -1223,6 +1223,7 @@
|
||||||
const labels = {
|
const labels = {
|
||||||
'note_created': t('event.noteCreated'),
|
'note_created': t('event.noteCreated'),
|
||||||
'note_updated': t('event.noteUpdated'),
|
'note_updated': t('event.noteUpdated'),
|
||||||
|
'note_deleted': 'Заметка удалена',
|
||||||
'file_added': t('event.fileAdded'),
|
'file_added': t('event.fileAdded'),
|
||||||
'file_deleted': t('event.fileDeleted'),
|
'file_deleted': t('event.fileDeleted'),
|
||||||
'file_renamed': t('event.fileRenamed'),
|
'file_renamed': t('event.fileRenamed'),
|
||||||
|
|
@ -1231,8 +1232,13 @@
|
||||||
'folder_added': t('event.folderAdded'),
|
'folder_added': t('event.folderAdded'),
|
||||||
'folder_deleted': t('event.folderDeleted'),
|
'folder_deleted': t('event.folderDeleted'),
|
||||||
'folder_renamed': t('event.folderRenamed'),
|
'folder_renamed': t('event.folderRenamed'),
|
||||||
|
'folder_moved': 'Папка перемещена',
|
||||||
'node_created': t('event.caseCreated'),
|
'node_created': t('event.caseCreated'),
|
||||||
'node_updated': t('event.caseUpdated'),
|
'node_updated': t('event.caseUpdated'),
|
||||||
|
'node_deleted': 'Узел удалён',
|
||||||
|
'action_created': 'Действие создано',
|
||||||
|
'action_done': 'Действие выполнено',
|
||||||
|
'worklog_added': 'Запись времени добавлена',
|
||||||
}
|
}
|
||||||
return labels[type] || type
|
return labels[type] || type
|
||||||
}
|
}
|
||||||
|
|
@ -1769,7 +1775,7 @@
|
||||||
{#each s.events as ev}
|
{#each s.events as ev}
|
||||||
<div class="suggestion-detail-event">
|
<div class="suggestion-detail-event">
|
||||||
<span class="suggestion-event-time">{formatTime(ev.createdAt)}</span>
|
<span class="suggestion-event-time">{formatTime(ev.createdAt)}</span>
|
||||||
<span class="suggestion-event-type">{t('event.' + ev.eventType) || ev.eventType}</span>
|
<span class="suggestion-event-type">{eventLabel(ev.eventType)}</span>
|
||||||
<span class="suggestion-event-title">{ev.title}</span>
|
<span class="suggestion-event-title">{ev.title}</span>
|
||||||
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
||||||
{#if ev.targetType === 'file' || ev.eventType.startsWith('file_')}
|
{#if ev.targetType === 'file' || ev.eventType.startsWith('file_')}
|
||||||
|
|
@ -1824,7 +1830,7 @@
|
||||||
{#each e._events as ev}
|
{#each e._events as ev}
|
||||||
<div class="journal-event-row">
|
<div class="journal-event-row">
|
||||||
<span class="journal-event-time">{formatTime(ev.createdAt)}</span>
|
<span class="journal-event-time">{formatTime(ev.createdAt)}</span>
|
||||||
<span class="journal-event-type">{t('event.' + ev.eventType) || ev.eventType}</span>
|
<span class="journal-event-type">{eventLabel(ev.eventType)}</span>
|
||||||
<span class="journal-event-title">{ev.title}</span>
|
<span class="journal-event-title">{ev.title}</span>
|
||||||
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
||||||
{#if ev.targetType === 'file' || ev.eventType.startsWith('file_')}
|
{#if ev.targetType === 'file' || ev.eventType.startsWith('file_')}
|
||||||
|
|
@ -1960,7 +1966,7 @@
|
||||||
{#each s.events as ev}
|
{#each s.events as ev}
|
||||||
<div class="suggestion-detail-event">
|
<div class="suggestion-detail-event">
|
||||||
<span class="suggestion-event-time">{formatTime(ev.createdAt)}</span>
|
<span class="suggestion-event-time">{formatTime(ev.createdAt)}</span>
|
||||||
<span class="suggestion-event-type">{t('event.' + ev.eventType) || ev.eventType}</span>
|
<span class="suggestion-event-type">{eventLabel(ev.eventType)}</span>
|
||||||
<span class="suggestion-event-title">{ev.title}</span>
|
<span class="suggestion-event-title">{ev.title}</span>
|
||||||
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
||||||
{#if ev.targetType === 'file' || ev.eventType.startsWith('file_')}
|
{#if ev.targetType === 'file' || ev.eventType.startsWith('file_')}
|
||||||
|
|
@ -2058,7 +2064,7 @@
|
||||||
{#each r._events as ev}
|
{#each r._events as ev}
|
||||||
<div class="journal-event-row">
|
<div class="journal-event-row">
|
||||||
<span class="journal-event-time">{formatTime(ev.createdAt)}</span>
|
<span class="journal-event-time">{formatTime(ev.createdAt)}</span>
|
||||||
<span class="journal-event-type">{t('event.' + ev.eventType) || ev.eventType}</span>
|
<span class="journal-event-type">{eventLabel(ev.eventType)}</span>
|
||||||
<span class="journal-event-title">{ev.title}</span>
|
<span class="journal-event-title">{ev.title}</span>
|
||||||
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -2114,7 +2120,7 @@
|
||||||
{#each s.events as ev}
|
{#each s.events as ev}
|
||||||
<div class="suggestion-detail-event">
|
<div class="suggestion-detail-event">
|
||||||
<span class="suggestion-event-time">{formatTime(ev.createdAt)}</span>
|
<span class="suggestion-event-time">{formatTime(ev.createdAt)}</span>
|
||||||
<span class="suggestion-event-type">{t('event.' + ev.eventType) || ev.eventType}</span>
|
<span class="suggestion-event-type">{eventLabel(ev.eventType)}</span>
|
||||||
<span class="suggestion-event-title">{ev.title}</span>
|
<span class="suggestion-event-title">{ev.title}</span>
|
||||||
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
<button class="link-btn" on:click={() => openNodeById(ev.nodeId)}>{t('common.open')}</button>
|
||||||
{#if ev.targetType === 'file' || ev.eventType.startsWith('file_')}
|
{#if ev.targetType === 'file' || ev.eventType.startsWith('file_')}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue