Skip to content

0.2.14

Choose a tag to compare

@github-actions github-actions released this 15 Aug 07:30
· 5 commits to main since this release
41e6f52

Added

  • A class can offer several destinations for its new notes. One folder and one template per class
    could not express what a class usually means: a Person met professionally starts from one template
    and lands in one folder, the same class for an artist starts from another and lands elsewhere. A
    class now keeps a list, each entry with a name, a folder and a template:

    newNotes:
      - name: Professional
        folder: 1_People/Contacts
        template: Templates/Person pro.md
      - name: Artist
        folder: 2_Artists
        template: Templates/Person artist.md

    Options → New notes lists them, one named row per destination showing its paths underneath,
    with Edit and Remove (which asks first, and never touches the folder or the template
    themselves). Add new opens the same modal as Edit.

    Creating a note asks which destination only when there is a choice — with one, it goes straight
    to the name.

    0.2.13's single fileClassNotesFolder/fileClassNoteTemplate pair is still read, as a list of
    one, so a vault configured then keeps working; saving the class through its options rewrites it as a
    list and clears the old keys, so a vault never carries two answers to the same question.

  • The wrench and the New button on every fileclass-table, not just the declared one. A vault
    keeps several tables of one class — Todo, Ongoing, Done, each with its own filter — and only
    one of them can be the view a class declares. The class is now read from whichever answers first:
    the class that declared the view, then the class the filter names, then the classes of the rows.

    The filter is read at both levels. Bases combines a base-wide filter with each view's own, and a
    base written before its views usually carries the class clause at the top —
    or: [fileClass.containsAny("Task"), file.hasTag("Task")] above a dozen status views, each
    filtering only on status. Reading the view alone found no class there, so a Tasks base got the
    generic buttons on every one of its views.

    A table about several classes keeps both buttons too: fileClass.containsAny("Book", "Comic")
    cannot say which class a new note should be, so the buttons read Manage fileClass and New note
    and ask once, offering only that table's classes.

    That fixes two reported cases the rows could not answer: an empty view showed no wrench at all
    (and kept the New button of the view before it, a leftover now cleared), and a view whose rows
    carried two classes — one note being both a Book and an Article — lost its New button and got a
    generic wrench, while its filter said fileClass.containsAny("Book") in plain sight.

  • A note created from a filtered table starts inside that table. From a Todo view — filtered
    status == "Todo" — the new note carries that status, instead of being made and immediately
    disappearing from the view that made it. Only what a filter fixes is used: an equality, or a
    single-value contains on a list field. !=, >, isEmpty() and a containsAny offering two
    values narrow without deciding, and nothing is invented there. A view that both filters and reads a
    relation applies both, the relation last.

    A value is only taken from a clause the filter always applies: anything under an or or a not
    is skipped, as is a formula clause (status == x || status == y). A view listing four statuses that
    all count as ongoing does not decide between them, and a note created from it would otherwise have
    been born with whichever one happened to be written first.

  • A fileclass-table groups its rows, from the view's own Group by. The setting sat in the
    Sort menu of every base and did nothing on an editable table: the rows came out flat while the
    native table beside them showed headings. Bases already hands a plugin view the grouped rows —
    the same groups, in the same order, measured — so this reads them rather than computing anything.
    Each run carries a heading naming the property and the value, in the native table's own classes so
    a theme styles it the same way; notes with nothing there group under None, last. Cells stay
    editable inside a group.

  • A link in a table cell shows its page preview on hover (with Ctrl/Cmd, if that is how the Page
    preview plugin is set). Obsidian does not watch the DOM for links a plugin drew — it listens for a
    hover-link event — so a link in a cell was the only link in the app that showed nothing.

  • A class's relatedViews row reads as relations, not as JSON. The panel printed the raw list
    of objects in the warning colour Obsidian keeps for values nobody can interpret — the same
    treatment the fields row used to get, on the other row where that value is the subject. It now
    shows one line per relation, author → Books › Book by author, each opening that base on that
    view. A relation whose base is missing is struck through and says so on hover; nothing is
    repaired, as with any other broken declaration.

  • A File or Media picker reaches every candidate, not the first hundred. Obsidian's suggester
    draws limit rows and says nothing about the rest — measured on a vault with 412 authors, the
    picker offered 100 of them, and the missing 312 looked exactly like notes that do not exist. It
    now draws a page at a time and adds the next when you reach the bottom, with 100 of 412 — scroll for more under the list while anything is held back. Typing still narrows first, and starts from
    one page again.

    MultiFile and MultiMedia never had this cap — they draw every candidate, and measured at
    2000 options the modal opens in 179 ms and a keystroke in its filter costs 29 ms, so nothing
    there needed changing.

  • An image gets the room it deserves, and the file name gets out of the way. Two surfaces
    changed, on use:

    • both media pickers are galleries — four per row, the picture large, the name under it —
      where they were lists of 20px thumbnails beside full-width file names, which is the one thing a
      cover is not chosen by. Picking several drops the switches with the rows: a card that is on says
      so by looking picked, and the whole card was already the target;
    • a table cell holding an image shows the picture alone. Dune.png next to the picture of
      Dune's cover says nothing the picture does not, and in a table it is the name that takes the
      width. The value is still there on hover.

    Unchanged where it was already right: the Properties row and the note-fields modal keep the
    thumbnail beside the link — that is where you check which file a value points at. A media value
    with no thumbnail (audio, a PDF) keeps its name everywhere, since there the name is all there is,
    and a picker over notes rather than pictures stays a list.

  • A class orders its inherited fields as freely as its own. When Book extends Media, the
    resolved order now runs from the root of the chain downMedia's fields, then Book's,
    which is the order the thing was built in, rather than the reverse. And that is only the default:
    a class's editor lists its whole resolved set, marks what it inherits from Media, and the arrows
    move any row, so Media's title, Book's author and Media's year can sit in that order
    if that is how the note reads best.

    A move writes fieldsOrder on that class:

    fieldsOrder:
      - title
      - author
      - year
      - editions
      - editions.format

    so the order belongs to the class declaring it: Media is untouched, and Comic — extending the
    same parent — keeps its own. Children are ordered among their siblings.

    An inherited row moves but does not edit: changing its type there would change it for every class
    extending Media, so the row offers to open Media instead.

    The declaration is built to age. A key naming a field that no longer resolves is ignored; a field
    the order does not name — because an ancestor gained one since — appears where the ancestor put
    it
    , behind the field it follows by default, not at the end below your own; and renaming a field
    carries its entry along, in every class that had placed it.

    On the class note, fieldsOrder is shown rather than edited: a list of strings is drawn as
    pills with a remove button each, and a stray click there would drop a field back to its default
    position without saying so. The row reads 20 fields, in this class's order, names them on hover,
    and opens the schema editor — where the arrows write it.

    One place applies it — where a resolved field set is built — so every surface follows: the
    note-fields modal, a synced view's columns, Reorder properties, the fields inserted into a new
    note. Measured on Book extends Media with Comic beside it: all four agree, Media and Comic
    unchanged.

  • A field can be read backwards by several views. A relation is often shown more than one way —
    Task.delegate as Delegate's ongoing tasks and as Delegate's done tasks — and only the first
    was a declared view: adopting the second silently replaced it, so one of the two lost its New
    task with …
    button and its seed. A class now keeps both:

    relatedViews:
      - field: delegate
        view: Tasks.base#Delegate's ongoing tasks
      - field: delegate
        view: Tasks.base#Delegate's done tasks

    Both get the button, and a note created from either arrives already pointing at the note the
    table is embedded in.

    A relation view about several classes now says so too. It cannot know what it will create —
    containsAny("Book", "Comic") decides nothing — but it knows what the note will be linked to, so
    the button reads New with <note> instead of New note. The class is asked for on click, and
    the link follows it: one of the table's classes that does not read this view backwards makes an
    ordinary note, which is what the tooltip says rather than promising the link. The pair is the identity, so declaring the same view twice for one field
    changes nothing. Where a single view used to be assumed — inserting a reverse relation into a
    note — you are asked which one this note should show, since guessing would be silent.

  • A class note's newNotes row reads as destinations, not as JSON. Third list of objects on
    that note, third time Obsidian printed the raw value in the colour it keeps for things nobody can
    interpret. One line per destination now, its name in front and the folder and template behind by
    their basenames — Reading list · Reading list › Book — with a click opening the class's options
    on the screen that manages them.

  • Related views are managed from the class's options — added, edited, and at last removed. A
    declaration could only be made from a view, by running Use this view for a relation while
    looking at it, and could not be removed at all short of editing the frontmatter by hand. That is a
    strange shape for something a class owns. Options → Related views now lists them
    (author → Books › Book by author), with Edit, Remove (which asks first) and Add new: pick
    the field, pick the view among every view of every base in the vault.

    Nothing there touches a base. A view that does not filter on the note it is read from is named
    as such, live, under the picker — embedded in a note it would show every row to every note — and
    left alone: adding that clause belongs to the command that adopts a view, where you are looking at
    the view itself.

    Removing the last one clears the key rather than leaving relatedViews: [].

  • A multiline option on Input and MultiInput (#177).
    Some Input fields hold a paragraph — a summary, an abstract, a rationale — and a one-line prompt
    is the wrong box for one: the text scrolls sideways past the edge, Enter submits instead of
    wrapping, and a line break has to be pasted in from somewhere else. With the option on, entry
    opens the text area the plugin already ships, in the vault's text font rather than the
    monospace of the JSON editor — prose is not code.

    Nothing else moves: one scalar string, the same validation, the same column, written as a YAML
    block scalar when it holds line breaks. On MultiInput it applies to each item, and the list
    editor around them is untouched. A template wins over it when both are set, since a template is
    a shape made of single-line parts.

  • The schema, in the editor (#185). In
    source mode the frontmatter is plain text, and typing there was the one path the schema never saw:
    no candidates, no validation, no allowed set — so the fastest way through a note was also the only
    unchecked one. Two things close it, split the way the field types are:

    • Values as you type them, for Select, Cycle and Multi — the types with a list to choose
      from, which is the same set Metadata Menu's own suggester covered. The candidates come from
      wherever the field declares them. A list works item by item (Enter on - Religion continues
      it, and what is already in the list is not offered again), and an inline themes: [] becomes the
      block form on choosing: the [] goes, the value arrives on its own line.
      When what you have typed matches none of them — which is what happens when you type after a
      value that is already there — the field's values are offered anyway rather than nothing, and
      since a choice replaces the whole value, picking one repairs the line.
    • Manage the field at the cursor, a command to bind to a hotkey, for everything else: a Date, a
      Number, a Duration, an Object have a controller rather than a list. It reads the caret the way
      the note is written, so a caret on year: 1990 inside the second edition opens that edition's
      editor. On a key no class declares it opens nothing and says so — a generic text box there would
      be a second way to write frontmatter unchecked. The caret returns to the field's line once the
      write lands, so a pass through a note survives the rewrite.

Changed

  • A sync keeps the columns you added to a managed view, and leaves them where they are. It set the
    order to file.name + the class's fields and deleted everything else, so a formula.Editions had to
    be re-added after every sync. Now every file.* and formula.* column stays in the slot it
    occupies — a formula.Room sitting third stays third, file.name stays wherever you put it — and
    only the remaining slots are refilled with the class's fields, in the class's order. Fields the view
    had no room for are appended; a second sync moves nothing.

    A bare column over a property no class declares is still removed: nothing can tell it apart from the
    leftover of a field the class used to have, and that same rule is what makes removing a field remove
    its column.

  • A single value written as a scalar is no longer flagged, unless it costs something. themes: Ecology instead of themes: [Ecology] was reported as invalid for every list type, which is a lot
    of noise in a vault migrated from Metadata Menu — it wrote single values that way. Measured on
    Bases: for a list of values, contains, containsAny and == match the scalar exactly as they
    match a list of one, so nothing can tell them apart and Multi/MultiInput now accept it.

    For a list of links it stays an error, because there the difference is visible: with the same
    link stored as a list on one note and a scalar on another,
    contributors.contains(this.file.asLink()) — the filter a reverse-relation view is built from —
    returns the first and skips the second, so the note vanishes from the table meant to list it. The
    message now names that instead of the shape: "contributors" is a single link, not a list — views
    filtering on it skip this note
    .

Fixed

  • A fieldsOrder written as field ids is read, instead of doing nothing. Metadata Menu wrote
    that very key as a list of ids (fieldsOrder: [jlBZN1, JKrPnA, …]), and 0.2.14 reads it as names
    — so a vault migrated from it declared an order and silently got the default. An entry is now read
    as a name at its level first and as a field id second, and the class note's row names the fields
    instead of repeating the ids: author · acquired · rating rather than jlBZN1 · JKrPnA · Fnb8cC.
    The next move through the schema editor rewrites the key in names, since ids are unique only
    within one class.

  • "Open its base" lands on the class's own view. It opened the base file and let Bases pick,
    which means the view listed first — usually not the class's, since a base is free to hold several
    and the managed one is generally appended. The class already declares which view is its own
    (baseView), so the tab now opens there. A class whose base does not hold that view — declared but
    never synced — still opens the base rather than asking Bases for something that is not there.