DevactionUI.FileTree (devaction_ui v0.2.3)

Copy Markdown View Source

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

node_data()

@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

totals(nodes)

@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}.

tree(assigns)

@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 to nil.
  • 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 to nil.
  • filters_label (:string) - the name of the group of filter pills for assistive technology. Defaults to nil.
  • findings_label (:string) - names the findings badge, as in "%{count} findings". Defaults to nil.
  • letters (:map) - the letter of each status. Defaults to %{modified: "M", added: "A", deleted: "D"}.
  • select_event (:any) - sent with path when a file is pressed. Defaults to "select_file".
  • toggle_event (:any) - sent with path when a folder is. Defaults to "toggle_folder".
  • filter_event (:any) - sent with filter when a pill is. Defaults to "filter_files".
  • search_event (:any) - sent with query as the person types. Defaults to "search_files".
  • target (:any) - a phx-target (a @myself) when used inside a LiveComponent. Defaults to nil.
  • class (:any) - Defaults to nil.
  • Global attributes are accepted.

Slots

  • pill - one filter pill. Accepts attributes:
    • id (:atom) (required) - :all, :findings or :new.
    • label (:string) (required)
  • legend - one entry of the legend of status letters. Accepts attributes:
    • status (:atom) (required) - :added, :modified or :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.

visible(nodes, open, filter \\ :all, query \\ "")

@spec visible([node_data()], [String.t()], :all | :findings | :new, String.t()) :: [
  map()
]

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.