The tree of changed files of a review: folders and files with a status letter (added, modified, deleted), a badge with the number of findings, a header with the count and the lines added and removed, a search field, filter pills and a legend of the letters.
The nodes come as data, a flat list in display order (nodes): %{path: "lib/a.ex", type: :file, name: "a.ex", depth: 1, status: :modified, additions: 18, deletions: 6, findings: 2, level: :risk}. A folder is
%{path: "lib", type: :dir}; name and depth default to the last segment of the path and its depth, and
a caller that compacts single-child folders (lib/sge/ as one row) sets them itself. A node is shown when
the folders above it are in open, so the server owns what is open, what is selected, the filter and the
search text; the component only draws it. visible/4 is that decision as a function, to use where the rows
themselves are needed.
Events, through attributes (a string or a %JS{}): select_event carries path when a file is pressed,
toggle_event carries path when a folder is, filter_event carries filter ("all", "findings" or
"new", the id of a :pill slot) and search_event carries query as the person types. While there is a
search text every folder is shown open, so the matches are not hidden inside a closed folder.
Keyboard (the DevactionUI.FileTree hook): ↑ ↓ Home End move the focus, → opens a closed folder or enters an
open one, ← closes it or goes to the parent, Enter and Space press the item. Only one item is in the Tab
order (roving tabindex). With search_key that key focuses the search field. Folders, files, the arrow and
the search take their icons through slots; without them the arrow is a typographic ›.
Summary
Functions
The lines added and removed by the files of the nodes: %{additions: 24, deletions: 9}.
The tree of changed files.
The nodes that show: files that pass the filter (:all, :findings or :new) and whose path contains
query (ignoring case), the folders that hold one of them (every folder when nothing filters), and only
those whose folders above are in open; with a query every folder counts as open. Each node comes with its
defaults filled in.
Types
@type node_data() :: %{ :path => String.t(), :type => :dir | :file, optional(:name) => String.t(), optional(:depth) => non_neg_integer(), optional(:status) => :added | :modified | :deleted | nil, optional(:additions) => non_neg_integer(), optional(:deletions) => non_neg_integer(), optional(:findings) => non_neg_integer(), optional(:level) => :risk | :warn }
Functions
@spec totals([node_data()]) :: %{ additions: non_neg_integer(), deletions: non_neg_integer() }
The lines added and removed by the files of the nodes: %{additions: 24, deletions: 9}.
@spec tree(map()) :: Phoenix.LiveView.Rendered.t()
The tree of changed files.
Attributes
id(:string) (required)label(:string) (required) - the name of the tree for assistive technology.title(:string) (required) - the heading of the panel, e.g. the files changed.nodes(:list) (required) - the folders and files in display order; see the module documentation for the shape.open(:list) - the paths of the folders that are open. Defaults to[].selected(:string) - the path of the selected file. Defaults tonil.filter(:atom) - which files show: all, those with findings or the new ones. Defaults to:all. Must be one of:all,:findings, or:new.query(:string) - the search text; files whose path contains it show. Defaults to"".search_label(:string) (required) - the name and the placeholder of the search field.search_key(:string) - a key that focuses the search field when the person is not typing, e.g."t". Defaults tonil.filters_label(:string) - the name of the group of filter pills for assistive technology. Defaults tonil.findings_label(:string) - names the findings badge, as in"%{count} findings". Defaults tonil.letters(:map) - the letter of each status. Defaults to%{modified: "M", added: "A", deleted: "D"}.select_event(:any) - sent withpathwhen a file is pressed. Defaults to"select_file".toggle_event(:any) - sent withpathwhen a folder is. Defaults to"toggle_folder".filter_event(:any) - sent withfilterwhen a pill is. Defaults to"filter_files".search_event(:any) - sent withqueryas the person types. Defaults to"search_files".target(:any) - aphx-target(a@myself) when used inside a LiveComponent. Defaults tonil.class(:any) - Defaults tonil.- Global attributes are accepted.
Slots
pill- one filter pill. Accepts attributes:id(:atom) (required) -:all,:findingsor:new.label(:string) (required)
legend- one entry of the legend of status letters. Accepts attributes:status(:atom) (required) -:added,:modifiedor:deleted.label(:string) (required)
search_hint- the shortcut shown at the end of the search field, e.g.T.empty- what shows when no file matches.search_icon- the icon of the search field.folder_icon- the icon of a folder.file_icon- the icon of a file.chevron_icon- the arrow of a folder; it turns when the folder opens.
The nodes that show: files that pass the filter (:all, :findings or :new) and whose path contains
query (ignoring case), the folders that hold one of them (every folder when nothing filters), and only
those whose folders above are in open; with a query every folder counts as open. Each node comes with its
defaults filled in.