feat: add trashed/trashedAt fields to VaultEntry
- Added trashed (boolean) and trashedAt (timestamp) to TypeScript VaultEntry - Added 'trash' filter to SidebarSelection union type - Added trashed/trashed_at fields to Rust VaultEntry struct and Frontmatter parser - Added 3 trashed mock entries for visual testing (recently trashed, 30+ days old, and dropped experiment) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,9 @@ pub struct VaultEntry {
|
||||
pub owner: Option<String>,
|
||||
pub cadence: Option<String>,
|
||||
pub archived: bool,
|
||||
pub trashed: bool,
|
||||
#[serde(rename = "trashedAt")]
|
||||
pub trashed_at: Option<u64>,
|
||||
#[serde(rename = "modifiedAt")]
|
||||
pub modified_at: Option<u64>,
|
||||
#[serde(rename = "createdAt")]
|
||||
@@ -60,6 +63,10 @@ struct Frontmatter {
|
||||
cadence: Option<String>,
|
||||
#[serde(rename = "Archived")]
|
||||
archived: Option<bool>,
|
||||
#[serde(rename = "Trashed")]
|
||||
trashed: Option<bool>,
|
||||
#[serde(rename = "Trashed at")]
|
||||
trashed_at: Option<String>,
|
||||
#[serde(rename = "Created at")]
|
||||
created_at: Option<String>,
|
||||
#[serde(rename = "Created time")]
|
||||
@@ -213,8 +220,8 @@ fn parse_frontmatter(data: &HashMap<String, serde_json::Value>) -> Frontmatter {
|
||||
/// Known non-relationship frontmatter keys to skip (case-insensitive comparison).
|
||||
/// Only skip keys that can never contain wikilinks.
|
||||
const SKIP_KEYS: &[&str] = &[
|
||||
"is a", "aliases", "status", "cadence", "archived", "created at", "created time",
|
||||
"icon", "color",
|
||||
"is a", "aliases", "status", "cadence", "archived", "trashed", "trashed at",
|
||||
"created at", "created time", "icon", "color",
|
||||
];
|
||||
|
||||
/// Check if a string contains a wikilink pattern `[[...]]`.
|
||||
@@ -364,6 +371,8 @@ pub fn parse_md_file(path: &Path) -> Result<VaultEntry, String> {
|
||||
owner: frontmatter.owner,
|
||||
cadence: frontmatter.cadence,
|
||||
archived: frontmatter.archived.unwrap_or(false),
|
||||
trashed: frontmatter.trashed.unwrap_or(false),
|
||||
trashed_at: frontmatter.trashed_at.as_deref().and_then(parse_iso_date),
|
||||
modified_at, created_at, file_size,
|
||||
icon: frontmatter.icon,
|
||||
color: frontmatter.color,
|
||||
|
||||
@@ -583,6 +583,45 @@ A **book** you're reading or have read. Track reading progress, notes, and key t
|
||||
- **Author**: The book's author
|
||||
- **Status**: Reading, Finished, Abandoned
|
||||
- **Rating**: 1-5 stars
|
||||
`,
|
||||
// --- Trashed entries ---
|
||||
'/Users/luca/Laputa/note/old-draft-notes.md': `---
|
||||
title: Old Draft Notes
|
||||
is_a: Note
|
||||
trashed: true
|
||||
trashed_at: ${new Date(Date.now() - 86400000 * 5).toISOString().slice(0, 10)}
|
||||
belongs_to:
|
||||
- "[[project/26q1-laputa-app]]"
|
||||
---
|
||||
|
||||
# Old Draft Notes
|
||||
|
||||
Some rough draft content that is no longer relevant. Moving to trash.
|
||||
`,
|
||||
'/Users/luca/Laputa/note/deprecated-api-notes.md': `---
|
||||
title: Deprecated API Notes
|
||||
is_a: Note
|
||||
trashed: true
|
||||
trashed_at: ${new Date(Date.now() - 86400000 * 35).toISOString().slice(0, 10)}
|
||||
---
|
||||
|
||||
# Deprecated API Notes
|
||||
|
||||
Old API documentation for the v1 endpoint. Replaced by v2 docs.
|
||||
`,
|
||||
'/Users/luca/Laputa/experiment/failed-seo-experiment.md': `---
|
||||
title: Failed SEO Experiment
|
||||
is_a: Experiment
|
||||
status: Dropped
|
||||
trashed: true
|
||||
trashed_at: ${new Date(Date.now() - 86400000 * 10).toISOString().slice(0, 10)}
|
||||
related_to:
|
||||
- "[[responsibility/grow-newsletter]]"
|
||||
---
|
||||
|
||||
# Failed SEO Experiment
|
||||
|
||||
Tried programmatic SEO pages. Results were negligible — trashing this.
|
||||
`,
|
||||
// --- Archived entries ---
|
||||
'/Users/luca/Laputa/project/25q3-website-redesign.md': `---
|
||||
@@ -672,6 +711,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: 'Luca Rossi',
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000,
|
||||
createdAt: null,
|
||||
fileSize: 2048,
|
||||
@@ -696,6 +737,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: 'Luca Rossi',
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 3600,
|
||||
createdAt: null,
|
||||
fileSize: 1024,
|
||||
@@ -725,6 +768,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: 'Matteo Cellini',
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 7200,
|
||||
createdAt: null,
|
||||
fileSize: 890,
|
||||
@@ -748,6 +793,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: 'Luca Rossi',
|
||||
cadence: 'Weekly',
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400,
|
||||
createdAt: null,
|
||||
fileSize: 512,
|
||||
@@ -771,6 +818,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: 'Matteo Cellini',
|
||||
cadence: 'Weekly',
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 2,
|
||||
createdAt: null,
|
||||
fileSize: 640,
|
||||
@@ -794,6 +843,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: 'Luca Rossi',
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400,
|
||||
createdAt: null,
|
||||
fileSize: 3200,
|
||||
@@ -818,6 +869,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 3600 * 5,
|
||||
createdAt: null,
|
||||
fileSize: 847,
|
||||
@@ -842,6 +895,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400,
|
||||
createdAt: null,
|
||||
fileSize: 560,
|
||||
@@ -865,6 +920,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 7,
|
||||
createdAt: null,
|
||||
fileSize: 320,
|
||||
@@ -887,6 +944,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 3600 * 2,
|
||||
createdAt: null,
|
||||
fileSize: 1200,
|
||||
@@ -910,6 +969,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 30,
|
||||
createdAt: null,
|
||||
fileSize: 256,
|
||||
@@ -933,6 +994,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 14,
|
||||
createdAt: null,
|
||||
fileSize: 180,
|
||||
@@ -956,6 +1019,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 3,
|
||||
createdAt: null,
|
||||
fileSize: 4200,
|
||||
@@ -979,6 +1044,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 7,
|
||||
createdAt: null,
|
||||
fileSize: 3800,
|
||||
@@ -1003,6 +1070,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 10,
|
||||
createdAt: null,
|
||||
fileSize: 5100,
|
||||
@@ -1027,6 +1096,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 320,
|
||||
@@ -1047,6 +1118,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 280,
|
||||
@@ -1067,6 +1140,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 310,
|
||||
@@ -1087,6 +1162,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 290,
|
||||
@@ -1107,6 +1184,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 200,
|
||||
@@ -1127,6 +1206,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 180,
|
||||
@@ -1147,6 +1228,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 170,
|
||||
@@ -1167,6 +1250,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 200,
|
||||
@@ -1187,6 +1272,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
createdAt: null,
|
||||
fileSize: 190,
|
||||
@@ -1208,6 +1295,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 30,
|
||||
createdAt: null,
|
||||
fileSize: 250,
|
||||
@@ -1228,6 +1317,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 30,
|
||||
createdAt: null,
|
||||
fileSize: 220,
|
||||
@@ -1249,6 +1340,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 5,
|
||||
createdAt: null,
|
||||
fileSize: 420,
|
||||
@@ -1271,6 +1364,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 14,
|
||||
createdAt: null,
|
||||
fileSize: 380,
|
||||
@@ -1281,6 +1376,81 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
icon: null,
|
||||
color: null,
|
||||
},
|
||||
// --- Trashed entries ---
|
||||
{
|
||||
path: '/Users/luca/Laputa/note/old-draft-notes.md',
|
||||
filename: 'old-draft-notes.md',
|
||||
title: 'Old Draft Notes',
|
||||
isA: 'Note',
|
||||
aliases: [],
|
||||
belongsTo: ['[[project/26q1-laputa-app]]'],
|
||||
relatedTo: [],
|
||||
status: null,
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: true,
|
||||
trashedAt: Date.now() / 1000 - 86400 * 5,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 10,
|
||||
createdAt: null,
|
||||
fileSize: 280,
|
||||
snippet: 'Some rough draft content that is no longer relevant. Moving to trash.',
|
||||
relationships: {
|
||||
'Belongs to': ['[[project/26q1-laputa-app]]'],
|
||||
'Type': ['[[type/note]]'],
|
||||
},
|
||||
icon: null,
|
||||
color: null,
|
||||
},
|
||||
{
|
||||
path: '/Users/luca/Laputa/note/deprecated-api-notes.md',
|
||||
filename: 'deprecated-api-notes.md',
|
||||
title: 'Deprecated API Notes',
|
||||
isA: 'Note',
|
||||
aliases: [],
|
||||
belongsTo: [],
|
||||
relatedTo: [],
|
||||
status: null,
|
||||
owner: null,
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: true,
|
||||
trashedAt: Date.now() / 1000 - 86400 * 35,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 40,
|
||||
createdAt: null,
|
||||
fileSize: 190,
|
||||
snippet: 'Old API documentation for the v1 endpoint. Replaced by v2 docs.',
|
||||
relationships: {
|
||||
'Type': ['[[type/note]]'],
|
||||
},
|
||||
icon: null,
|
||||
color: null,
|
||||
},
|
||||
{
|
||||
path: '/Users/luca/Laputa/experiment/failed-seo-experiment.md',
|
||||
filename: 'failed-seo-experiment.md',
|
||||
title: 'Failed SEO Experiment',
|
||||
isA: 'Experiment',
|
||||
aliases: [],
|
||||
belongsTo: [],
|
||||
relatedTo: ['[[responsibility/grow-newsletter]]'],
|
||||
status: 'Dropped',
|
||||
owner: 'Luca Rossi',
|
||||
cadence: null,
|
||||
archived: false,
|
||||
trashed: true,
|
||||
trashedAt: Date.now() / 1000 - 86400 * 10,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 15,
|
||||
createdAt: null,
|
||||
fileSize: 340,
|
||||
snippet: 'Tried programmatic SEO pages. Results were negligible — trashing this.',
|
||||
relationships: {
|
||||
'Related to': ['[[responsibility/grow-newsletter]]'],
|
||||
'Type': ['[[type/experiment]]'],
|
||||
},
|
||||
icon: null,
|
||||
color: null,
|
||||
},
|
||||
// --- Archived entries ---
|
||||
{
|
||||
path: '/Users/luca/Laputa/project/25q3-website-redesign.md',
|
||||
@@ -1294,6 +1464,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: 'Luca Rossi',
|
||||
cadence: null,
|
||||
archived: true,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
icon: null,
|
||||
color: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 120,
|
||||
@@ -1317,6 +1489,8 @@ const MOCK_ENTRIES: VaultEntry[] = [
|
||||
owner: 'Luca Rossi',
|
||||
cadence: null,
|
||||
archived: true,
|
||||
trashed: false,
|
||||
trashedAt: null,
|
||||
icon: null,
|
||||
color: null,
|
||||
modifiedAt: Date.now() / 1000 - 86400 * 90,
|
||||
|
||||
@@ -10,6 +10,8 @@ export interface VaultEntry {
|
||||
owner: string | null
|
||||
cadence: string | null
|
||||
archived: boolean
|
||||
trashed: boolean
|
||||
trashedAt: number | null
|
||||
modifiedAt: number | null
|
||||
createdAt: number | null
|
||||
fileSize: number
|
||||
@@ -37,7 +39,7 @@ export interface ModifiedFile {
|
||||
}
|
||||
|
||||
export type SidebarSelection =
|
||||
| { kind: 'filter'; filter: 'all' | 'favorites' | 'archived' }
|
||||
| { kind: 'filter'; filter: 'all' | 'favorites' | 'archived' | 'trash' }
|
||||
| { kind: 'sectionGroup'; type: string }
|
||||
| { kind: 'entity'; entry: VaultEntry }
|
||||
| { kind: 'topic'; entry: VaultEntry }
|
||||
|
||||
Reference in New Issue
Block a user