1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# lib/pro_tacts/admin is ignored by the Steepfile — built on Phlex,
# which ships no signatures — but checked code still calls its views, and
# a checked file cannot reference a constant nothing declares. This
# holds exactly that entry surface; the views' own files carry none.
# When Phlex gets a stand-in under sig/gems and admin is checked for
# real, delete this.
module ProTacts
  module Admin
    class ContactsShow
      def self.call: (contact: Contact, login: String, groups: Array[ListedGroup], all_groups: Array[Store::GroupChoice], changes: Array[Store::Change], ?notice: String?) -> String
    end

    # `aside` is a Phlex component, which has no type here: phlex
    # ships no signatures and the views are ignored (see the
    # Steepfile).
    class ContactsEdit
      def self.call: (contact: Contact, login: String, ?notice: String?, ?action: String?, ?back: [String, String]?, ?aside: untyped, ?fields: untyped, ?lead: untyped, ?sidebar: untyped, ?save: String?) -> String
    end

    class Dashboard
      RECENT_LIMIT: Integer
      def self.call: (recent: Array[Store::RecentContact], upcoming: Array[Store::UpcomingBirthday], login: String, ?notice: String?) -> String
    end

    class SearchResults
      LIMIT: Integer
      def self.new: (contacts: Array[Store::RecentContact], groups: Array[Group], ?recent: bool, ?more: Integer) -> instance
      def call: () -> String
    end

    class SearchPage
      def self.call: (login: String, query: String, results: SearchResults) -> String
    end

    class ContactsIndex
      def self.call: (contacts: Array[ListedContact], groups: Array[ListedGroup], login: String) -> String
    end

    class GroupsIndex
      def self.call: (groups: Array[Group], login: String, ?notice: String?) -> String
    end

    class GroupsShow
      def self.call: (group: Group, contacts: Array[ListedContact], changes: Array[Store::GroupChange], login: String) -> String
      def self.moved: (Array[Store::GroupChange] changes) -> Array[String]
    end

    # Rendered by the views that tag groups; the routes read how many
    # members a tag names, to list that many.
    class GroupTag
      SHOWN: Integer
    end

    class GroupsEdit
      def self.call: (group: Group, login: String, ?notice: String?) -> String
    end

    class GroupsMembers
      def self.call: (group: Group, contacts: Array[ListedContact], login: String) -> String
    end

    class GroupsNew
      def self.call: (contact: Contact, contacts: Array[ListedContact], login: String, ?notice: String?) -> String
    end

    class DeviceSetup
      def self.call: (hostname: String, login: String, name: String) -> String
    end

    class ImportUpload
      def self.call: (login: String, ?notice: String?) -> String
    end

    # Rendered into ContactsEdit rather than called, so these are the
    # views here whose `new` is what checked code reaches for.
    class ImportOriginal
      def self.new: (card: ::ProTacts::VCard, dropped: Array[::ProTacts::VCard::Parser::Line]) -> instance
    end

    class ImportGroups
      def self.new: (groups: Array[::ProTacts::Store::GroupChoice], joined: Array[String], named: Array[String], ?was: Array[String]) -> instance
    end

    class ImportTarget
      def self.new: (row: String, matches: Array[Contact | ListedContact], into: Contact?) -> instance
    end

    class ImportSidebar
      def self.new: (upload: String, rows: Array[[String, Integer, Integer]], saved: Hash[String, String], current: Integer) -> instance
    end

    class ImportSaved
      def self.call: (contact: Contact, login: String, groups: Array[ListedGroup], all_groups: Array[Store::GroupChoice], aside: untyped, sidebar: untyped, edit: String, land: String, ?notice: String?) -> String
    end

    # Its name_label is the import's list rows' (Web#import_row), and
    # its search_key is the fold Search matches on.
    module Format
      def self.name_label: (Contact | ListedContact contact) -> String
      def self.search_key: (String value) -> String
    end

    # Rendered by Dashboard, not called from checked code; only
    # its LIMIT is read, in web/contacts.rb.
    class UpcomingBirthdays
      LIMIT: Integer
    end
  end
end