feat(capture): capture to an arbitrary frontmatter property (#466)#1363
Conversation
) Mirror the existing #tag capture target with a frontmatter-property filter: property:type=draft capture into a note whose `type` frontmatter is draft property:type presence mode (note has the field, any value) property:type=draft|folder:Notes|exclude-tag:done + the shared {{FILE}}/{{FIELD}} pipe filters - new pure parsePropertyTarget (single classifier shared by engine + preflight) - getMarkdownFilesWithProperty + null/false/0-safe frontmatterValueMatches, case-insensitive key+value, array any-match, reuses EnhancedFieldSuggestionFileFilter for the pipe filters - resolveCaptureTarget property branch (before the .base/folder checks) + selectFileWithProperty mirroring selectFileWithTag; empty-field aborts cleanly - preflight one-page dropdown for property targets, skipped when the value is tokenized (mirrors the tokenized-file-path escape) - builder shows a neutral "filters notes by frontmatter property" hint instead of a misleading fake-path preview - docs + tests (parser, value matcher, query, preflight) Closes #466
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds Changesproperty: capture target feature
Sequence Diagram(s)sequenceDiagram
participant User
participant CaptureChoiceEngine
participant parsePropertyTarget
participant getMarkdownFilesWithProperty
participant InputSuggester
User->>CaptureChoiceEngine: trigger capture (captureTo = "property:status=active")
CaptureChoiceEngine->>parsePropertyTarget: "property:status=active"
parsePropertyTarget-->>CaptureChoiceEngine: {kind:"property", field:"status", value:"active", filter:{}}
CaptureChoiceEngine->>getMarkdownFilesWithProperty: app, "status", "active", {}
getMarkdownFilesWithProperty-->>CaptureChoiceEngine: TFile[] (matching frontmatter)
CaptureChoiceEngine->>InputSuggester: ordered candidates list
InputSuggester-->>CaptureChoiceEngine: selected TFile path
CaptureChoiceEngine-->>User: capture written to selected file
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install timed out. The project may have too many dependencies for the sandbox. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying quickadd with
|
| Latest commit: |
86b9a14
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://169220dc.quickadd.pages.dev |
| Branch Preview URL: | https://chhoumann-466-capture-to-pro.quickadd.pages.dev |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3bc258737d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| valueExists: (v) => | ||
| existingMatched.has(v) || | ||
| existingMatched.has(v.replace(/\.md$/i, "")), |
There was a problem hiding this comment.
Check custom property targets against the whole vault
When create-file is enabled for a property:type=... target, typing the path or basename of an existing note that does not currently match the property is not found in existingMatched, so the suggester offers it as “Create new note”. Selecting that custom row returns the path, and the later fileExists branch writes to the existing nonmatching file via onFileExists, bypassing the property filter and not creating anything. The existence check should consider the whole vault or reject existing non-matches, not just filesWithProperty.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed in efa22c9. The tag/property pickers now share selectFileFromSet, whose valueExists is vault-aware: typing an existing note that doesn't match the filter no longer shows a "Create new note" row and isn't offered, so it can't be captured into. Verified e2e — typing an existing type: note note yields no rows; a genuinely new name still offers create.
- fix Codex P2: extract shared selectFileFromSet helper for the tag/property
pickers and make the "Create new note" existence check vault-aware, so typing
an existing non-matching note no longer mislabels as "create" nor captures
into that file (it isn't offered) — also removes the selectFileWithTag clone
- docs: the pipe-filter grammar is {{FIELD}} (which honors |folder:), not {{FILE}}
- docs + code comment: value matching is always case-insensitive; only
folder/tag/exclude-* pipes are honored (others are inert)
- builder: exclude property targets from canvas detection so property:...canvas
never offers a meaningless canvas-node picker
- tests: engine-level resolveCaptureTarget property cases (incl. .md-bearing
value not misrouting, pipe filters, empty-field abort)
|
Review round (commit efa22c9) — addressed an ultracode multi-lens review + the Codex P2:
Full suite green (2325 passing), build + lint + svelte-check clean; e2e re-verified in the worktree vault. @codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: efa22c9441
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| valueExists: (value) => | ||
| existingTagged.has(value) || | ||
| existingTagged.has(value.replace(/\.md$/i, "")), | ||
| existingInSet.has(value) || | ||
| existingInSet.has(value.replace(/\.md$/i, "")) || | ||
| this.vaultFileExists(value), |
There was a problem hiding this comment.
Suppress create for nested existing basenames
When the tag/property picker has create-if-missing enabled and the user types the basename of an existing non-matching note in a folder, this valueExists check still returns false because vaultFileExists() only probes getAbstractFileByPath(value[.md/.canvas]), e.g. Foo/Foo.md, and never scans vault basenames such as Archive/Foo.md. In that scenario the modal still offers Create new note: Foo, mislabeling an existing note and creating a duplicate root note instead of suppressing the create row.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 86b9a14: replaced vaultFileExists with captureTargetAlreadyExists, which also checks a vault-wide basename set (built once per picker, O(1) per keystroke). Verified e2e — typing the basename of a non-matching subfolder note now shows no rows; a genuinely new name still offers create.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/engine/CaptureChoiceEngine.ts`:
- Around line 851-860: The vaultFileExists method only checks for direct path
matches and does not search for existing files by basename in other directories,
causing false negatives for notes that exist outside the root folder. Extend
vaultFileExists to also iterate through all files in the vault and check if any
file's basename (without extension) matches the provided value, in addition to
the existing direct path checks. This will ensure that valueExists correctly
identifies existing notes regardless of their folder location and prevent false
"creatable" labels that could lead to accidental duplicate note creation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 2bd82b1c-0f73-4203-b193-ab4674f2dadb
📒 Files selected for processing (5)
docs/docs/Choices/CaptureChoice.mdsrc/engine/CaptureChoiceEngine.selection.test.tssrc/engine/CaptureChoiceEngine.tssrc/gui/ChoiceBuilder/components/CaptureTargetSetting.sveltesrc/utils/propertyTarget.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- docs/docs/Choices/CaptureChoice.md
- src/gui/ChoiceBuilder/components/CaptureTargetSetting.svelte
- src/utils/propertyTarget.ts
…er (#466) Follow-up to the vault-aware picker fix: vaultFileExists only probed exact paths, so typing the bare basename of an existing note that lives in a subfolder still offered "Create new note" (mislabeling it / risking a duplicate). Replace it with captureTargetAlreadyExists, which checks exact path candidates AND a vault-wide basename set (built once per picker, O(1) per keystroke). Flagged by Codex (P2) and CodeRabbit (major) on the previous commit.
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex review |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
Closes #466.
What
Adds a
property:Capture target that pre-filters the note picker by an arbitrary frontmatter field, mirroring the existing#tagtarget.Capture tovalueproperty:type=drafttypeequalsdraftproperty:typetypefield (any value)property:type=draft|folder:Notes|exclude-tag:done{{FILE}}/{{FIELD}}pipe filters (folder/tag/exclude-folder/exclude-tag/exclude-file)property:status={{VALUE}}type: [draft, idea]) match if any element equals the value.Why this syntax
A bare
{{type: draft}}would clash with the{{FIELD:type}}format grammar (the original report ran into exactly this).property:is an unambiguous prefix that mirrors the#tag sigil, survives the engine'sformatFileNamepass, and can't collide with a real vault path.|is reserved for the pipe-filter grammar, reusing the sameFieldSuggestionParser/EnhancedFieldSuggestionFileFilterthat{{FILE:}}uses.How
Mirrors the tag target across the three resolution sites plus the builder, with a single shared classifier so the engine and the one-page preflight can never disagree:
src/utils/propertyTarget.ts— pureparsePropertyTarget, the single source of truth used by both engine and preflight.src/utils/vaultQueries.ts—getMarkdownFilesWithProperty+ purefrontmatterValueMatches(guardsnullbeforeString()coercion; usesString(raw)sofalse/0match; array any-match; case-insensitive key lookup).src/engine/CaptureChoiceEngine.ts—propertybranch inresolveCaptureTarget(placed before the.base/folder/extension checks so a value containing.md///.basecan't misroute) +selectFileWithProperty; an empty field name aborts with a clear message.src/preflight/collectChoiceRequirements.ts— populates the one-page/CLI target dropdown for property targets, skipped when the value is tokenized (mirrors the tokenized-file-path escape).CaptureTargetSetting.svelte— shows a neutral "filters notes by frontmatter property" hint instead of a misleading fake-path preview.docs/docs/Choices/CaptureChoice.md.Verification
Type: Draft(case-insensitive key + value), an array member, and a sub-folder note;|folder:intersected correctly; presence mode listed all typed notes;property:aborted cleanly with no junk file; a full capture wrote below the preserved YAML frontmatter.Release / migration impact
New, additive capture-target syntax. No migration. Existing
Capture tovalues are unaffected (nothing else starts withproperty:).Summary by CodeRabbit
Release Notes
New Features
property:field=valuecapture targets (frontmatter-based) andproperty:fieldpresence-mode selection.|...syntax.Documentation