onlylogs 0.11.0 โ†’ 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +251 -77
  3. data/app/assets/images/onlylogs/favicon/apple-touch-icon.png +0 -0
  4. data/app/assets/images/onlylogs/favicon/favicon-96x96.png +0 -0
  5. data/app/assets/images/onlylogs/favicon/favicon.ico +0 -0
  6. data/app/assets/images/onlylogs/favicon/favicon.svg +1 -3
  7. data/app/assets/images/onlylogs/favicon/web-app-manifest-192x192.png +0 -0
  8. data/app/assets/images/onlylogs/favicon/web-app-manifest-512x512.png +0 -0
  9. data/app/assets/images/onlylogs/logo.png +0 -0
  10. data/app/assets/javascripts/onlylogs/clusterize.js +26 -1
  11. data/app/channels/onlylogs/logs_channel.rb +14 -9
  12. data/app/controllers/concerns/onlylogs/authentication.rb +26 -0
  13. data/app/controllers/onlylogs/application_controller.rb +1 -18
  14. data/app/controllers/onlylogs/queries_controller.rb +70 -0
  15. data/app/controllers/onlylogs/viewer_controller.rb +7 -0
  16. data/app/javascript/onlylogs/controllers/keyboard_shortcuts_controller.js +131 -21
  17. data/app/javascript/onlylogs/controllers/log_cursor_controller.js +286 -0
  18. data/app/javascript/onlylogs/controllers/log_streamer_controller.js +42 -2
  19. data/app/javascript/onlylogs/controllers/match_highlight_controller.js +82 -0
  20. data/app/javascript/onlylogs/controllers/queries_controller.js +470 -0
  21. data/app/javascript/onlylogs/controllers/range_slider_controller.js +5 -4
  22. data/app/javascript/onlylogs/controllers/text_selection_controller.js +136 -15
  23. data/app/models/onlylogs/file.rb +14 -5
  24. data/app/models/onlylogs/grep.rb +13 -6
  25. data/app/models/onlylogs/queries_record.rb +28 -0
  26. data/app/models/onlylogs/query.rb +29 -0
  27. data/app/views/onlylogs/logs/index.html.erb +1 -1
  28. data/app/views/onlylogs/shared/_log_container.html.erb +165 -27
  29. data/app/views/onlylogs/shared/_log_container_styles.html.erb +729 -44
  30. data/app/views/onlylogs/shared/_shortcuts_dialog.html.erb +62 -0
  31. data/bin/super_grep +7 -0
  32. data/bin/super_ripgrep +5 -0
  33. data/config/routes.rb +1 -0
  34. data/lib/onlylogs/configuration.rb +14 -1
  35. data/lib/onlylogs/http_device.rb +28 -13
  36. data/lib/onlylogs/version.rb +1 -1
  37. data/lib/onlylogs.rb +4 -0
  38. metadata +38 -1
@@ -8,6 +8,7 @@
8
8
  autoscroll = local_assigns[:autoscroll] != false
9
9
  filter = local_assigns[:filter] || ""
10
10
  regexp_mode = local_assigns[:regexp_mode] == true
11
+ case_insensitive = local_assigns[:case_insensitive] == true
11
12
  # A file nothing writes to any more (no drain attached, a rotated log) has nothing
12
13
  # to follow, so live mode is not offered at all and the viewer opens in search.
13
14
  mode = live_enabled ? (local_assigns[:mode] || "live") : "static"
@@ -19,21 +20,35 @@
19
20
  raise SecurityError, "File path not allowed" unless Onlylogs.file_path_permitted?(log_file_path)
20
21
 
21
22
  encrypted_log_file_path = Onlylogs::SecureFilePath.encrypt(log_file_path)
23
+
24
+ shortcut_modifier = request.user_agent.to_s.match?(/Macintosh|iPhone|iPad/) ? "control" : "alt"
25
+ shortcut_modifier_label = shortcut_modifier == "control" ? "โŒƒ Control" : "Alt"
22
26
  %>
23
27
 
24
- <div data-controller="log-streamer text-selection keyboard-shortcuts"
28
+ <div data-controller="log-streamer text-selection keyboard-shortcuts log-cursor match-highlight queries"
29
+ data-queries-log-file-path-value="<%= encrypted_log_file_path %>"
30
+ data-queries-endpoint-value="<%= onlylogs.queries_path %>"
31
+ data-keyboard-shortcuts-modifier-value="<%= shortcut_modifier %>"
25
32
  data-log-streamer-file-path-value="<%= encrypted_log_file_path %>"
26
33
  <% if start_position.present? %>data-log-streamer-start-position-value="<%= start_position %>"<% end %>
27
34
  <% if end_position.present? %>data-log-streamer-end-position-value="<%= end_position %>"<% end %>
28
35
  data-log-streamer-filter-value="<%= filter %>"
29
36
  data-log-streamer-auto-scroll-value="<%= autoscroll %>"
30
37
  data-log-streamer-regexp-mode-value="<%= regexp_mode %>"
38
+ data-log-streamer-case-insensitive-value="<%= case_insensitive %>"
31
39
  data-log-streamer-mode-value="<%= mode %>"
32
40
  data-log-streamer-live-enabled-value="<%= live_enabled %>"
33
41
  data-log-streamer-file-size-value="<%= file_size %>"
34
- data-action="text-selection:start->log-streamer#pauseForSelection text-selection:search->log-streamer#switchToSearch"
42
+ data-action="text-selection:start->log-streamer#pauseForSelection text-selection:search->log-streamer#switchToSearch
43
+ log-streamer:cleared->log-cursor#reset log-streamer:cleared->text-selection#forgetSelection log-streamer:context-line->log-cursor#placeAt
44
+ log-streamer:rendering->text-selection#saveSelection log-streamer:rendered->text-selection#restoreSelection
45
+ log-cursor:move->log-streamer#pauseForSelection log-cursor:select->text-selection#showForSelection
46
+ log-cursor:search->text-selection#searchSelectedText keyboard-shortcuts:lines->log-cursor#focus
47
+ log-streamer:context-line->queries#cleared"
35
48
  class="onlylogs-log-container" >
36
- <div data-log-streamer-target="logLines" data-text-selection-target="logLines" id="scrollArea" class="onlylogs-log-lines clusterize-scroll">
49
+ <div data-log-streamer-target="logLines" data-text-selection-target="logLines" data-log-cursor-target="lines" data-match-highlight-target="lines"
50
+ data-action="keydown->log-cursor#navigate mousedown->log-cursor#pointAt focusin->log-cursor#activate"
51
+ id="scrollArea" class="onlylogs-log-lines clusterize-scroll">
37
52
  <div id="contentArea" class="clusterize-content">
38
53
  </div>
39
54
  </div>
@@ -55,8 +70,8 @@
55
70
  data-text-selection-target="button"
56
71
  class="onlylogs-context-menu hidden-button"
57
72
  data-action="click->text-selection#searchSelectedText"
58
- title="Search selected text">
59
- ๐Ÿ” Search
73
+ title="Search selected text (Enter)">
74
+ ๐Ÿ” Search <kbd>โ†ต</kbd>
60
75
  </button>
61
76
 
62
77
  <div class="onlylogs-log-toolbar">
@@ -66,68 +81,179 @@
66
81
  <button type="button"
67
82
  class="onlylogs-mode-switch__button"
68
83
  data-onlylogs-mode-button="live"
84
+ data-onlylogs-shortcut="l"
69
85
  data-log-streamer-target="liveButton"
70
- data-keyboard-shortcuts-target="liveButton"
71
86
  data-action="click->log-streamer#switchToLive"
72
87
  aria-pressed="<%= mode == "live" %>"
73
- title="Follow the file as it is written (L)">
74
- <span>โ–ถ <u>L</u>ive</span>
88
+ title="Follow the file as it is written">
89
+ <span>โ–ถ Live</span>
75
90
  </button>
76
91
  <button type="button"
77
92
  class="onlylogs-mode-switch__button"
78
93
  data-onlylogs-mode-button="static"
94
+ data-onlylogs-shortcut="s"
79
95
  data-log-streamer-target="searchButton"
80
- data-keyboard-shortcuts-target="searchButton"
81
96
  data-action="click->log-streamer#switchToSearch"
82
97
  aria-pressed="<%= mode != "live" %>"
83
- title="Search what is already in the file (S)">
84
- <span>๐Ÿ” <u>S</u>earch</span>
98
+ title="Search what is already in the file">
99
+ <span>๐Ÿ” Search</span>
85
100
  </button>
86
101
  </div>
87
102
  <% end %>
88
- <div>
89
- <label class="toolbar-label">
103
+ <div class="onlylogs-query">
104
+ <label class="toolbar-label" for="onlylogs-filter">
90
105
  <span data-onlylogs-mode="live">Follow:</span>
91
106
  <span data-onlylogs-mode="static">Query:</span>
92
- <div class="filter-input-wrapper">
107
+ </label>
108
+ <div class="saved-searches" data-queries-target="box" data-action="keydown->queries#navigate">
109
+ <div class="filter-input-wrapper" data-onlylogs-shortcut="q">
93
110
  <input type="text"
111
+ id="onlylogs-filter"
94
112
  name="filter"
95
113
  value="<%= filter %>"
96
114
  placeholder="<%= mode == "live" ? "follow lines matchingโ€ฆ" : "search the whole fileโ€ฆ" %>"
115
+ spellcheck="false"
116
+ autocomplete="off"
97
117
  data-log-streamer-target="filterInput"
98
118
  data-text-selection-target="filterInput"
99
- data-action="input->log-streamer#applyFilter">
119
+ data-keyboard-shortcuts-target="filterInput"
120
+ data-match-highlight-target="filterInput"
121
+ data-action="input->log-streamer#applyFilter input->queries#refresh keydown.enter->log-cursor#focus keydown.esc->log-cursor#focus">
122
+ <button type="button"
123
+ data-action="click->log-streamer#clearFilter click->queries#cleared"
124
+ data-onlylogs-shortcut="x"
125
+ class="filter-input-button clear-filter-button"
126
+ aria-label="Clear the query"
127
+ title="Clear the query">
128
+ <svg width="10" height="10" viewBox="0 0 10 10" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" aria-hidden="true"><path d="M2 2l6 6M8 2l-6 6"/></svg>
129
+ </button>
130
+ <button type="button"
131
+ class="filter-input-button saved-searches__toggle"
132
+ data-queries-target="toggle"
133
+ data-onlylogs-shortcut="v"
134
+ data-action="queries#toggle"
135
+ aria-haspopup="true"
136
+ aria-expanded="false"
137
+ aria-controls="onlylogs-saved-searches-panel"
138
+ aria-label="Saved searches"
139
+ title="Saved searches">
140
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11"/><circle cx="4.5" cy="6" r="1" fill="currentColor"/><circle cx="4.5" cy="12" r="1" fill="currentColor"/><circle cx="4.5" cy="18" r="1" fill="currentColor"/></svg>
141
+ <span class="saved-searches__count" data-queries-target="count"></span>
142
+ </button>
100
143
  <button type="button"
101
- data-action="click->log-streamer#clearFilter"
102
- class="clear-filter-button"
103
- title="Clear filter">
104
- ร—
144
+ class="filter-input-button saved-searches__star"
145
+ data-queries-target="star"
146
+ data-onlylogs-shortcut="f"
147
+ data-action="queries#toggleSave"
148
+ aria-haspopup="true"
149
+ aria-expanded="false"
150
+ aria-controls="onlylogs-save-search-panel"
151
+ disabled>
152
+ <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.9l-5.2 2.7 1-5.8-4.3-4.1 5.9-.9z"/></svg>
105
153
  </button>
106
154
  </div>
155
+
156
+ <div id="onlylogs-saved-searches-panel" class="saved-searches__panel" data-queries-target="panel" hidden>
157
+ <div class="saved-searches__header">
158
+ <span class="saved-searches__title">Saved searches</span>
159
+ <span class="saved-searches__keys">โ†‘โ†“ move ยท โ†ต apply ยท esc</span>
160
+ </div>
161
+ <ul class="saved-searches__list" data-queries-target="list" aria-label="Saved searches"></ul>
162
+ <div class="saved-searches__empty" data-queries-target="empty" hidden>
163
+ <strong>No saved searches yet</strong>
164
+ <span>Type a pattern, then click the star in the field to keep it here.</span>
165
+ </div>
166
+ <div class="saved-searches__footer" data-queries-target="footer" hidden>
167
+ <button type="button" class="saved-searches__footer-button" data-action="queries#openSave">
168
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linejoin="round" aria-hidden="true"><path d="M12 3.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.9l-5.2 2.7 1-5.8-4.3-4.1 5.9-.9z"/></svg>
169
+ <span data-queries-target="footerLabel"></span>
170
+ </button>
171
+ </div>
172
+ </div>
173
+
174
+ <div id="onlylogs-save-search-panel" class="saved-searches__panel saved-searches__panel--save" data-queries-target="savePanel" hidden>
175
+ <div class="save-search__summary">
176
+ <span class="save-search__title" data-queries-target="saveTitle"></span>
177
+ <div class="save-search__current">
178
+ <code data-queries-target="saveFilter"></code>
179
+ <span data-queries-target="saveFlags"></span>
180
+ </div>
181
+ </div>
182
+ <form class="save-search__form" data-action="queries#save">
183
+ <label for="onlylogs-save-search-name">Name</label>
184
+ <div class="save-search__row">
185
+ <input type="text"
186
+ id="onlylogs-save-search-name"
187
+ maxlength="255"
188
+ placeholder="e.g. Errors"
189
+ autocomplete="off"
190
+ data-queries-target="name"
191
+ data-action="input->queries#nameChanged">
192
+ <button type="submit" data-queries-target="saveButton" disabled>Save</button>
193
+ </div>
194
+ <p class="save-search__hint" data-queries-target="hint"></p>
195
+ </form>
196
+ <div class="save-search__saved" data-queries-target="savedRow" hidden>
197
+ <span>Already in your saved searches.</span>
198
+ <button type="button" data-action="queries#removeCurrent">Remove</button>
199
+ </div>
200
+ </div>
201
+
202
+ <template data-queries-target="rowTemplate">
203
+ <li class="saved-search">
204
+ <button type="button" class="saved-search__apply" data-action="queries#apply">
205
+ <span class="saved-search__line">
206
+ <span class="saved-search__name"></span>
207
+ <svg class="saved-search__check" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-label="Current search"><path d="M5 12.5l4.5 4.5L19 7.5"/></svg>
208
+ <span class="saved-search__edited">edited</span>
209
+ </span>
210
+ <span class="saved-search__line">
211
+ <code class="saved-search__filter"></code>
212
+ <span class="saved-search__flags"></span>
213
+ </span>
214
+ </button>
215
+ <input type="text" class="saved-search__rename-input" maxlength="255" autocomplete="off" hidden
216
+ data-action="keydown->queries#renameKey blur->queries#commitRename">
217
+ <button type="button" class="saved-search__action saved-search__rename" data-action="queries#rename">
218
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20h4L19 9l-4-4L4 16z"/></svg>
219
+ </button>
220
+ <button type="button" class="saved-search__action saved-search__delete" data-action="queries#destroy">
221
+ <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M9 7V5h6v2M6 7l1 13h10l1-13"/></svg>
222
+ <span class="saved-search__delete-label">Delete?</span>
223
+ </button>
224
+ </li>
225
+ </template>
226
+ </div>
227
+ </div>
228
+ <div>
229
+ <label class="toolbar-label" data-onlylogs-shortcut="r">
230
+ <input id="regexpMode" type="checkbox" <%= regexp_mode ? "checked" : "" %> name="regexpMode" data-log-streamer-target="regexpMode" data-text-selection-target="regexpMode" data-match-highlight-target="regexpMode" data-action="change->log-streamer#toggleRegexpMode change->queries#refresh">
231
+ <span>Regexp</span>
107
232
  </label>
108
233
  </div>
109
234
  <div>
110
- <label class="toolbar-label">
111
- <input id="regexpMode" type="checkbox" <%= regexp_mode ? "checked" : "" %> name="regexpMode" data-log-streamer-target="regexpMode" data-text-selection-target="regexpMode" data-action="change->log-streamer#toggleRegexpMode">
112
- <span><u>R</u>egexp</span>
235
+ <label class="toolbar-label" data-onlylogs-shortcut="i">
236
+ <input id="caseInsensitive" type="checkbox" <%= case_insensitive ? "checked" : "" %> name="caseInsensitive" data-log-streamer-target="caseInsensitive" data-match-highlight-target="caseInsensitive" data-action="change->log-streamer#toggleCaseInsensitive change->queries#refresh">
237
+ <span>Ignore case</span>
113
238
  </label>
114
239
  </div>
115
240
  <div data-onlylogs-mode="live">
116
- <label class="toolbar-label">
117
- <input id="autoscroll" type="checkbox" <%= autoscroll ? "checked" : "" %> name="autoscroll" data-log-streamer-target="autoscroll" data-keyboard-shortcuts-target="autoscroll" data-action="change->log-streamer#toggleAutoScroll">
118
- <span><u>A</u>utoscroll</span>
241
+ <label class="toolbar-label" data-onlylogs-shortcut="a">
242
+ <input id="autoscroll" type="checkbox" <%= autoscroll ? "checked" : "" %> name="autoscroll" data-log-streamer-target="autoscroll" data-action="change->log-streamer#toggleAutoScroll">
243
+ <span>Autoscroll</span>
119
244
  </label>
120
245
  </div>
121
246
  <div data-onlylogs-mode="live">
122
247
  <button type="button"
123
248
  data-log-streamer-target="searchWholeFileButton"
124
249
  class="search-whole-file-button"
250
+ data-onlylogs-shortcut="w"
125
251
  data-action="click->log-streamer#searchWholeFile"
126
252
  title="Search this text across the whole file">
127
253
  Search whole file โ†’
128
254
  </button>
129
255
  </div>
130
- <div class="range-slider-wrapper" data-onlylogs-mode="static">
256
+ <div class="range-slider-wrapper" data-onlylogs-mode="static" data-onlylogs-shortcut="g">
131
257
  <%= render "onlylogs/shared/range_slider",
132
258
  start_name: "start_position",
133
259
  end_name: "end_position",
@@ -140,6 +266,7 @@
140
266
  <button type="button"
141
267
  data-action="click->log-streamer#resetRange"
142
268
  class="reset-range-button"
269
+ data-onlylogs-shortcut="0"
143
270
  title="Reset to full file">
144
271
  โ†ป
145
272
  </button>
@@ -148,6 +275,7 @@
148
275
  <button type="button"
149
276
  data-log-streamer-target="stopButton"
150
277
  class="stop-search-button hidden-button"
278
+ data-onlylogs-shortcut="."
151
279
  data-action="click->log-streamer#stopSearch"
152
280
  title="Stop current search">
153
281
  โ–  Stop
@@ -156,7 +284,8 @@
156
284
  </div>
157
285
 
158
286
  <div class="onlylogs-toolbar-row onlylogs-toolbar-row--status">
159
- <span data-log-streamer-target="results" class="results-text">Results: 0</span>
287
+ <span data-log-streamer-target="results" class="results-text" data-onlylogs-shortcut="j"
288
+ data-action="click->log-cursor#focus">Results: 0</span>
160
289
  <span data-log-streamer-target="message" class="status-message"></span>
161
290
  <div class="onlylogs-toolbar-row__end">
162
291
  <% unless Onlylogs.ripgrep_enabled? %>
@@ -168,12 +297,21 @@
168
297
  <button type="button"
169
298
  data-log-streamer-target="clearButton"
170
299
  class="clear-logs-button"
300
+ data-onlylogs-shortcut="c"
171
301
  data-action="click->log-streamer#clearLogs"
172
302
  aria-label="Clear all log lines"
173
303
  title="Clear all log lines">
174
304
  ๐Ÿ—‘
175
305
  </button>
306
+ <button type="button"
307
+ class="shortcuts-button"
308
+ data-action="keyboard-shortcuts#openHelp"
309
+ aria-label="Keyboard shortcuts"
310
+ title="Keyboard shortcuts (?) ยท hold <%= shortcut_modifier_label %> to see the letters">
311
+ โŒจ
312
+ </button>
176
313
  <span data-log-streamer-target="websocketStatus" class="websocket-status websocket-status--disconnected" title="WebSocket Disconnected">๐Ÿ”ด</span>
314
+ <%= render "onlylogs/shared/shortcuts_dialog", modifier_label: shortcut_modifier_label %>
177
315
  </div>
178
316
  </div>
179
317
  </div>