fix: restrict inbox to captured artifacts
This commit is contained in:
parent
58a74acbf6
commit
2e86229350
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -16,7 +16,7 @@
|
||||||
background: #13131f;
|
background: #13131f;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<script type="module" crossorigin src="/assets/main-4y6wyoK9.js"></script>
|
<script type="module" crossorigin src="/assets/main-O6a-DCWF.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/main-es_E5H-H.css">
|
<link rel="stylesheet" crossorigin href="/assets/main-es_E5H-H.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
||||||
|
|
@ -2,30 +2,30 @@ package main
|
||||||
|
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestListInboxNodesReturnsOnlyUnassignedRoots(t *testing.T) {
|
func TestListInboxNodesReturnsOnlyCapturedArtifacts(t *testing.T) {
|
||||||
app, _ := setupTestApp(t)
|
app, _ := setupTestApp(t)
|
||||||
|
|
||||||
unassigned, err := app.CreateNodeFromTemplate("", "Unassigned Root", "folder.default")
|
manual, err := app.CreateNodeFromTemplate("", "Manual Root", "folder.default")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("create unassigned root: %v", err)
|
t.Fatalf("create manual root: %v", err)
|
||||||
}
|
}
|
||||||
inbox, err := app.CreateNodeFromTemplate("", "Inbox Root", "folder.default")
|
legacyInbox, err := app.CreateNodeFromTemplate("", "Legacy Inbox Root", "folder.default")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("create inbox root: %v", err)
|
t.Fatalf("create legacy inbox root: %v", err)
|
||||||
}
|
}
|
||||||
assigned, err := app.CreateNodeFromTemplate("", "Assigned Root", "folder.default")
|
captured, err := app.CreateNodeFromTemplate("", "Captured Artifact", "folder.default")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("create assigned root: %v", err)
|
t.Fatalf("create captured artifact: %v", err)
|
||||||
}
|
}
|
||||||
child, err := app.CreateNodeFromTemplate(unassigned.ID, "Nested Child", "folder.default")
|
child, err := app.CreateNodeFromTemplate(captured.ID, "Nested Child", "folder.default")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("create child: %v", err)
|
t.Fatalf("create child: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := app.db.Exec(`UPDATE nodes SET section = 'inbox' WHERE id = ?`, inbox.ID); err != nil {
|
if _, err := app.db.Exec(`UPDATE nodes SET section = 'inbox' WHERE id = ?`, legacyInbox.ID); err != nil {
|
||||||
t.Fatalf("mark inbox: %v", err)
|
t.Fatalf("mark legacy inbox: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := app.db.Exec(`UPDATE nodes SET section = 'projects' WHERE id = ?`, assigned.ID); err != nil {
|
if err := app.nodes.MetaSet(captured.ID, "capture.inbox", "true"); err != nil {
|
||||||
t.Fatalf("mark assigned: %v", err)
|
t.Fatalf("mark captured: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
list, err := app.ListInboxNodes()
|
list, err := app.ListInboxNodes()
|
||||||
|
|
@ -37,14 +37,14 @@ func TestListInboxNodesReturnsOnlyUnassignedRoots(t *testing.T) {
|
||||||
for _, item := range list {
|
for _, item := range list {
|
||||||
got[item.ID] = true
|
got[item.ID] = true
|
||||||
}
|
}
|
||||||
if !got[unassigned.ID] {
|
if !got[captured.ID] {
|
||||||
t.Fatal("unassigned root missing from inbox")
|
t.Fatal("captured artifact missing from inbox")
|
||||||
}
|
}
|
||||||
if !got[inbox.ID] {
|
if got[manual.ID] {
|
||||||
t.Fatal("section=inbox root missing from inbox")
|
t.Fatal("manual root should not be in inbox")
|
||||||
}
|
}
|
||||||
if got[assigned.ID] {
|
if got[legacyInbox.ID] {
|
||||||
t.Fatal("assigned root should not be in inbox")
|
t.Fatal("section=inbox root without capture metadata should not be in inbox")
|
||||||
}
|
}
|
||||||
if got[child.ID] {
|
if got[child.ID] {
|
||||||
t.Fatal("nested child should not be in inbox")
|
t.Fatal("nested child should not be in inbox")
|
||||||
|
|
|
||||||
|
|
@ -2004,7 +2004,6 @@
|
||||||
<h2>{t('nav.inbox')}</h2>
|
<h2>{t('nav.inbox')}</h2>
|
||||||
<p>{t('inbox.subtitle')}</p>
|
<p>{t('inbox.subtitle')}</p>
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-primary btn-sm" on:click={openCreateRoot}>+ {t('nav.createNode')}</button>
|
|
||||||
</div>
|
</div>
|
||||||
{#if inboxNodes.length === 0}
|
{#if inboxNodes.length === 0}
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export default {
|
||||||
'nav.createInside': 'Create inside',
|
'nav.createInside': 'Create inside',
|
||||||
'nav.createNode': 'Create element',
|
'nav.createNode': 'Create element',
|
||||||
'nav.moveToRoot': 'Move to root',
|
'nav.moveToRoot': 'Move to root',
|
||||||
'inbox.subtitle': 'Root items without an assigned section',
|
'inbox.subtitle': 'Captured materials that still need to be assigned to cases',
|
||||||
'inbox.empty': 'No unprocessed items',
|
'inbox.empty': 'No unprocessed items',
|
||||||
'trash.openFolder': 'Open trash folder',
|
'trash.openFolder': 'Open trash folder',
|
||||||
'trash.empty': 'Trash is empty',
|
'trash.empty': 'Trash is empty',
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export default {
|
||||||
'nav.createNode': 'Создать элемент',
|
'nav.createNode': 'Создать элемент',
|
||||||
'nav.moveToRoot': 'Переместить в корень',
|
'nav.moveToRoot': 'Переместить в корень',
|
||||||
|
|
||||||
'inbox.subtitle': 'Корневые элементы без назначенного раздела',
|
'inbox.subtitle': 'Захваченные материалы, которые нужно разложить по делам',
|
||||||
'inbox.empty': 'Неразобранных элементов нет',
|
'inbox.empty': 'Неразобранных элементов нет',
|
||||||
|
|
||||||
'trash.openFolder': 'Открыть папку корзины',
|
'trash.openFolder': 'Открыть папку корзины',
|
||||||
|
|
|
||||||
|
|
@ -169,10 +169,13 @@ func (r *Repository) ListRoots(includeDeleted bool) ([]Node, error) {
|
||||||
return scanNodes(rows)
|
return scanNodes(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListInboxRoots returns active root nodes that are not assigned to a specific section.
|
// ListInboxRoots returns active root capture artifacts explicitly marked for inbox.
|
||||||
func (r *Repository) ListInboxRoots(includeDeleted bool) ([]Node, error) {
|
func (r *Repository) ListInboxRoots(includeDeleted bool) ([]Node, error) {
|
||||||
q := `SELECT ` + nodeColumns + ` FROM nodes
|
q := `SELECT ` + nodeColumns + ` FROM nodes
|
||||||
WHERE parent_id IS NULL AND COALESCE(section, '') IN ('', 'inbox')`
|
WHERE parent_id IS NULL
|
||||||
|
AND id IN (
|
||||||
|
SELECT node_id FROM node_meta WHERE key = 'capture.inbox' AND value = 'true'
|
||||||
|
)`
|
||||||
if !includeDeleted {
|
if !includeDeleted {
|
||||||
q += " AND deleted_at IS NULL"
|
q += " AND deleted_at IS NULL"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,8 @@ async function runReadyScenario(cdp, url) {
|
||||||
|
|
||||||
await clickText(cdp, '.nav-item', 'Неразобранное')
|
await clickText(cdp, '.nav-item', 'Неразобранное')
|
||||||
await assertText(cdp, 'Неразобранное', 'inbox: system view opens')
|
await assertText(cdp, 'Неразобранное', 'inbox: system view opens')
|
||||||
await assertText(cdp, 'Inbox Smoke Item', 'inbox: unassigned item visible')
|
await assertText(cdp, 'Inbox Smoke Item', 'inbox: captured item visible')
|
||||||
|
await assertEval(cdp, `!document.querySelector('.inbox-screen')?.innerText.includes('Manual Root Item')`, 'inbox: manual root is hidden')
|
||||||
await screenshot(cdp, 'inbox.png')
|
await screenshot(cdp, 'inbox.png')
|
||||||
await clickText(cdp, '.inbox-item-actions .btn', 'Открыть')
|
await clickText(cdp, '.inbox-item-actions .btn', 'Открыть')
|
||||||
await assertText(cdp, 'Inbox Smoke Item', 'inbox: item opens from list')
|
await assertText(cdp, 'Inbox Smoke Item', 'inbox: item opens from list')
|
||||||
|
|
@ -577,7 +578,8 @@ function wailsMockSource() {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ id: 'node-client', title: 'Smoke Client', type: 'client', section: 'clients', createdAt: now, has_children: false, children: [] },
|
{ id: 'node-client', title: 'Smoke Client', type: 'client', section: 'clients', createdAt: now, has_children: false, children: [] },
|
||||||
{ id: 'node-inbox', title: 'Inbox Smoke Item', type: 'folder', section: '', createdAt: now, has_children: false, children: [] },
|
{ id: 'node-inbox', title: 'Inbox Smoke Item', type: 'folder', section: '', captureInbox: true, createdAt: now, has_children: false, children: [] },
|
||||||
|
{ id: 'node-manual-root', title: 'Manual Root Item', type: 'folder', section: '', createdAt: now, has_children: false, children: [] },
|
||||||
],
|
],
|
||||||
notes: {
|
notes: {
|
||||||
'node-project': [{ id: 'note-1', title: 'Smoke note', createdAt: now }],
|
'node-project': [{ id: 'note-1', title: 'Smoke note', createdAt: now }],
|
||||||
|
|
@ -685,7 +687,7 @@ function wailsMockSource() {
|
||||||
],
|
],
|
||||||
ListWorkspaceTree: async () => clone(state.nodes),
|
ListWorkspaceTree: async () => clone(state.nodes),
|
||||||
ListWorkspaceChildren: async (id) => clone(childrenOf(id)),
|
ListWorkspaceChildren: async (id) => clone(childrenOf(id)),
|
||||||
ListInboxNodes: async () => clone(state.nodes.filter((node) => !node.parent_id && (!node.section || node.section === 'inbox'))),
|
ListInboxNodes: async () => clone(state.nodes.filter((node) => !node.parent_id && node.captureInbox === true)),
|
||||||
ListTrash: async () => clone({
|
ListTrash: async () => clone({
|
||||||
trashPath: '/tmp/verstak-smoke-vault/.verstak/trash',
|
trashPath: '/tmp/verstak-smoke-vault/.verstak/trash',
|
||||||
nodes: [{ id: 'node-trash', title: 'Trash Smoke Folder', type: 'folder', fsPath: 'Trash Smoke Folder', deletedAt: now }],
|
nodes: [{ id: 'node-trash', title: 'Trash Smoke Folder', type: 'folder', fsPath: 'Trash Smoke Folder', deletedAt: now }],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue