mbeditor 0.13.0 → 0.14.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +157 -1
- data/app/assets/javascripts/mbeditor/application.js +3 -1
- data/app/assets/javascripts/mbeditor/audit_log.js +165 -0
- data/app/assets/javascripts/mbeditor/collaboration_service.js +264 -22
- data/app/assets/javascripts/mbeditor/components/ChangelogView.js +89 -94
- data/app/assets/javascripts/mbeditor/components/CodeReviewPanel.js +6 -9
- data/app/assets/javascripts/mbeditor/components/CollapsibleSection.js +12 -7
- data/app/assets/javascripts/mbeditor/components/CombinedDiffViewer.js +20 -0
- data/app/assets/javascripts/mbeditor/components/DiffViewer.js +1 -1
- data/app/assets/javascripts/mbeditor/components/EditorPanel.js +440 -334
- data/app/assets/javascripts/mbeditor/components/FileHistoryPanel.js +6 -9
- data/app/assets/javascripts/mbeditor/components/FileTree.js +26 -12
- data/app/assets/javascripts/mbeditor/components/GitPanel.js +3 -0
- data/app/assets/javascripts/mbeditor/components/Gutter.js +51 -0
- data/app/assets/javascripts/mbeditor/components/ImportDialog.js +9 -1
- data/app/assets/javascripts/mbeditor/components/LogPanel.js +3 -44
- data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +1322 -1431
- data/app/assets/javascripts/mbeditor/components/ModelGraph.js +94 -37
- data/app/assets/javascripts/mbeditor/components/ProblemsPanel.js +82 -72
- data/app/assets/javascripts/mbeditor/components/QuickOpenDialog.js +121 -81
- data/app/assets/javascripts/mbeditor/components/SettingsModal.js +342 -0
- data/app/assets/javascripts/mbeditor/components/ShortcutHelp.js +2 -1
- data/app/assets/javascripts/mbeditor/components/TabBar.js +67 -98
- data/app/assets/javascripts/mbeditor/editor_plugins.js +694 -306
- data/app/assets/javascripts/mbeditor/file_import.js +13 -15
- data/app/assets/javascripts/mbeditor/file_service.js +46 -57
- data/app/assets/javascripts/mbeditor/git_service.js +15 -1
- data/app/assets/javascripts/mbeditor/history_service.js +5 -13
- data/app/assets/javascripts/mbeditor/search_service.js +29 -2
- data/app/assets/javascripts/mbeditor/tab_manager.js +135 -54
- data/app/assets/javascripts/mbeditor/websocket_service.js +13 -5
- data/app/assets/stylesheets/mbeditor/application.css +6 -1
- data/app/assets/stylesheets/mbeditor/editor.css +762 -297
- data/app/assets/stylesheets/mbeditor/glass.css +163 -0
- data/app/assets/stylesheets/mbeditor/themes.css +90 -30
- data/app/channels/mbeditor/collaboration_channel.rb +25 -6
- data/app/controllers/mbeditor/application_controller.rb +26 -3
- data/app/controllers/mbeditor/editors_controller.rb +125 -465
- data/app/services/mbeditor/archive_service.rb +137 -0
- data/app/services/mbeditor/collaboration_doc_store.rb +180 -12
- data/app/services/mbeditor/duplicate_content_scanner.rb +105 -0
- data/app/services/mbeditor/editor_state_service.rb +14 -51
- data/app/services/mbeditor/file_history_service.rb +222 -0
- data/app/services/mbeditor/git_info_service.rb +6 -0
- data/app/services/mbeditor/js_globals_service.rb +12 -1
- data/app/services/mbeditor/js_syntax_check_service.rb +42 -16
- data/app/services/mbeditor/lint_service.rb +137 -0
- data/app/services/mbeditor/locked_json_file.rb +67 -0
- data/app/services/mbeditor/process_runner.rb +32 -0
- data/app/services/mbeditor/rubocop_run_service.rb +17 -5
- data/app/services/mbeditor/ruby_lsp_result_translator.rb +226 -0
- data/app/services/mbeditor/schema_service.rb +8 -2
- data/app/services/mbeditor/search_replace_service.rb +19 -2
- data/app/services/mbeditor/test_runner_service.rb +3 -56
- data/app/views/layouts/mbeditor/application.html.erb +1 -1
- data/lib/mbeditor/audit_log.rb +203 -0
- data/lib/mbeditor/configuration.rb +6 -9
- data/lib/mbeditor/rack/pending_migration_bypass.rb +15 -9
- data/lib/mbeditor/route_map.rb +4 -1
- data/lib/mbeditor/ruby_lsp_client.rb +82 -14
- data/lib/mbeditor/version.rb +1 -1
- data/lib/mbeditor.rb +1 -0
- data/lib/tasks/mbeditor.rake +23 -0
- metadata +14 -3
- data/app/assets/javascripts/mbeditor/components/TestRunPanel.js +0 -312
|
@@ -1,12 +1,46 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
|
|
4
3
|
|
|
5
4
|
var _React = React;
|
|
6
5
|
var useState = _React.useState;
|
|
7
6
|
var useEffect = _React.useEffect;
|
|
8
7
|
var useRef = _React.useRef;
|
|
9
8
|
|
|
9
|
+
var menuItem = function menuItem(icon, label, onClick) {
|
|
10
|
+
return React.createElement(
|
|
11
|
+
'div',
|
|
12
|
+
{ className: 'ide-tab-context-menu-item', onClick: onClick },
|
|
13
|
+
React.createElement('i', { className: icon }),
|
|
14
|
+
label
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Clamps a position:fixed, content-sized popup menu into the viewport.
|
|
19
|
+
// The menu is already rendered at its raw (possibly off-screen) cursor
|
|
20
|
+
// position via inline style, so its size can only be known by measuring
|
|
21
|
+
// the real element — nudge it back on-screen if it overflows. Shared by
|
|
22
|
+
// the tab-strip menu here and the explorer context menu in MbeditorApp.js.
|
|
23
|
+
window.clampMenuIntoView = function clampMenuIntoView(el) {
|
|
24
|
+
if (!el) return;
|
|
25
|
+
var MARGIN = 4;
|
|
26
|
+
var rect = el.getBoundingClientRect();
|
|
27
|
+
var left = rect.left;
|
|
28
|
+
var top = rect.top;
|
|
29
|
+
|
|
30
|
+
if (rect.right > window.innerWidth - MARGIN) {
|
|
31
|
+
left = Math.max(MARGIN, window.innerWidth - MARGIN - rect.width);
|
|
32
|
+
}
|
|
33
|
+
if (rect.bottom > window.innerHeight - MARGIN) {
|
|
34
|
+
var above = rect.top - rect.height;
|
|
35
|
+
top = above >= MARGIN ? above : MARGIN;
|
|
36
|
+
}
|
|
37
|
+
if (left < MARGIN) left = MARGIN;
|
|
38
|
+
if (top < MARGIN) top = MARGIN;
|
|
39
|
+
|
|
40
|
+
if (left !== rect.left) el.style.left = left + 'px';
|
|
41
|
+
if (top !== rect.top) el.style.top = top + 'px';
|
|
42
|
+
};
|
|
43
|
+
|
|
10
44
|
var TabBar = function TabBar(_ref) {
|
|
11
45
|
var tabs = _ref.tabs;
|
|
12
46
|
var activeId = _ref.activeId;
|
|
@@ -29,27 +63,24 @@ var TabBar = function TabBar(_ref) {
|
|
|
29
63
|
|
|
30
64
|
var _useState = useState(null);
|
|
31
65
|
|
|
32
|
-
var _useState2 = _slicedToArray(_useState, 2);
|
|
33
66
|
|
|
34
|
-
var draggingTabId =
|
|
35
|
-
var setDraggingTabId =
|
|
67
|
+
var draggingTabId = _useState[0];
|
|
68
|
+
var setDraggingTabId = _useState[1];
|
|
36
69
|
|
|
37
70
|
var _useState3 = useState(null);
|
|
38
71
|
|
|
39
|
-
var _useState4 = _slicedToArray(_useState3, 2);
|
|
40
72
|
|
|
41
|
-
var tabContextMenu =
|
|
42
|
-
var setTabContextMenu =
|
|
73
|
+
var tabContextMenu = _useState3[0];
|
|
74
|
+
var setTabContextMenu = _useState3[1];
|
|
75
|
+
var tabContextMenuRef = useRef(null);
|
|
43
76
|
|
|
44
77
|
var _useState5 = useState(null);
|
|
45
|
-
var
|
|
46
|
-
var
|
|
47
|
-
var setDropTargetTabId = _useState6[1];
|
|
78
|
+
var dropTargetTabId = _useState5[0];
|
|
79
|
+
var setDropTargetTabId = _useState5[1];
|
|
48
80
|
|
|
49
81
|
var _useState7 = useState(null);
|
|
50
|
-
var
|
|
51
|
-
var
|
|
52
|
-
var setDropTargetSide = _useState8[1];
|
|
82
|
+
var dropTargetSide = _useState7[0];
|
|
83
|
+
var setDropTargetSide = _useState7[1];
|
|
53
84
|
|
|
54
85
|
var getTabMarkerClass = function getTabMarkerClass(tab) {
|
|
55
86
|
var tabMarkers = markers[tab.id] || [];
|
|
@@ -93,6 +124,11 @@ var TabBar = function TabBar(_ref) {
|
|
|
93
124
|
return function () { document.removeEventListener('mousedown', handler); };
|
|
94
125
|
}, [tabContextMenu]);
|
|
95
126
|
|
|
127
|
+
// Clamp into view whenever the menu opens at a new position.
|
|
128
|
+
useEffect(function () {
|
|
129
|
+
if (tabContextMenu) window.clampMenuIntoView(tabContextMenuRef.current);
|
|
130
|
+
}, [tabContextMenu]);
|
|
131
|
+
|
|
96
132
|
return React.createElement(
|
|
97
133
|
React.Fragment,
|
|
98
134
|
null,
|
|
@@ -104,7 +140,7 @@ var TabBar = function TabBar(_ref) {
|
|
|
104
140
|
}
|
|
105
141
|
} },
|
|
106
142
|
tabs.map(function (tab) {
|
|
107
|
-
var isSpecial = tab.isCommitGraph || tab.isDiff || tab.isPreview
|
|
143
|
+
var isSpecial = tab.isCommitGraph || tab.isDiff || tab.isPreview;
|
|
108
144
|
return React.createElement(
|
|
109
145
|
'div',
|
|
110
146
|
{
|
|
@@ -178,7 +214,7 @@ var TabBar = function TabBar(_ref) {
|
|
|
178
214
|
}
|
|
179
215
|
}
|
|
180
216
|
},
|
|
181
|
-
React.createElement('i', { className: 'tab-item-icon ' + (
|
|
217
|
+
React.createElement('i', { className: 'tab-item-icon ' + (window.getFileIcon ? window.getFileIcon(tab.name) : 'far fa-file-code') }),
|
|
182
218
|
React.createElement(
|
|
183
219
|
'div',
|
|
184
220
|
{ className: 'tab-item-name' },
|
|
@@ -190,14 +226,12 @@ var TabBar = function TabBar(_ref) {
|
|
|
190
226
|
'●'
|
|
191
227
|
),
|
|
192
228
|
React.createElement(
|
|
193
|
-
'
|
|
229
|
+
'button',
|
|
194
230
|
{
|
|
231
|
+
type: 'button',
|
|
195
232
|
className: 'tab-close',
|
|
196
|
-
// No role="button" here: the host app's Pico CSS skins
|
|
197
|
-
// [role=button] with a primary background and form padding, which
|
|
198
|
-
// turns this into a blue square. It is a plain div with a tooltip,
|
|
199
|
-
// as it was — Ctrl+W is the keyboard path.
|
|
200
233
|
title: 'Close ' + tab.name + (tab.dirty ? ' (unsaved changes)' : ''),
|
|
234
|
+
'aria-label': 'Close ' + tab.name + (tab.dirty ? ' (unsaved changes)' : ''),
|
|
201
235
|
onClick: function (e) {
|
|
202
236
|
e.stopPropagation();
|
|
203
237
|
onClose(tab.id);
|
|
@@ -222,6 +256,7 @@ var TabBar = function TabBar(_ref) {
|
|
|
222
256
|
'div',
|
|
223
257
|
{
|
|
224
258
|
className: 'ide-tab-context-menu',
|
|
259
|
+
ref: tabContextMenuRef,
|
|
225
260
|
style: {
|
|
226
261
|
position: 'fixed',
|
|
227
262
|
top: tabContextMenu.y,
|
|
@@ -236,85 +271,19 @@ var TabBar = function TabBar(_ref) {
|
|
|
236
271
|
},
|
|
237
272
|
onMouseDown: function(e) { e.stopPropagation(); }
|
|
238
273
|
},
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
style: { padding: '6px 14px', cursor: 'pointer', color: '#ccc', fontSize: '12px', display: 'flex', alignItems: 'center', gap: '8px' },
|
|
244
|
-
onMouseEnter: function(e) { e.currentTarget.style.background = '#094771'; },
|
|
245
|
-
onMouseLeave: function(e) { e.currentTarget.style.background = 'transparent'; },
|
|
246
|
-
onClick: function() { setTabContextMenu(null); onClose(tabContextMenu.tab.id); }
|
|
247
|
-
},
|
|
248
|
-
React.createElement('i', { className: 'fas fa-times', style: { width: '14px', textAlign: 'center' } }),
|
|
249
|
-
'Close'
|
|
250
|
-
),
|
|
251
|
-
onCloseOthers && React.createElement(
|
|
252
|
-
'div',
|
|
253
|
-
{
|
|
254
|
-
className: 'ide-tab-context-menu-item',
|
|
255
|
-
style: { padding: '6px 14px', cursor: 'pointer', color: '#ccc', fontSize: '12px', display: 'flex', alignItems: 'center', gap: '8px' },
|
|
256
|
-
onMouseEnter: function(e) { e.currentTarget.style.background = '#094771'; },
|
|
257
|
-
onMouseLeave: function(e) { e.currentTarget.style.background = 'transparent'; },
|
|
258
|
-
onClick: function() { setTabContextMenu(null); onCloseOthers(tabContextMenu.tab.id); }
|
|
259
|
-
},
|
|
260
|
-
React.createElement('i', { className: 'fas fa-times-circle', style: { width: '14px', textAlign: 'center' } }),
|
|
261
|
-
'Close Others'
|
|
262
|
-
),
|
|
263
|
-
onCloseSaved && React.createElement(
|
|
264
|
-
'div',
|
|
265
|
-
{
|
|
266
|
-
className: 'ide-tab-context-menu-item',
|
|
267
|
-
style: { padding: '6px 14px', cursor: 'pointer', color: '#ccc', fontSize: '12px', display: 'flex', alignItems: 'center', gap: '8px' },
|
|
268
|
-
onMouseEnter: function(e) { e.currentTarget.style.background = '#094771'; },
|
|
269
|
-
onMouseLeave: function(e) { e.currentTarget.style.background = 'transparent'; },
|
|
270
|
-
onClick: function() { setTabContextMenu(null); onCloseSaved(); }
|
|
271
|
-
},
|
|
272
|
-
React.createElement('i', { className: 'fas fa-check', style: { width: '14px', textAlign: 'center' } }),
|
|
273
|
-
'Close Saved'
|
|
274
|
-
),
|
|
275
|
-
onCloseAll && React.createElement(
|
|
276
|
-
'div',
|
|
277
|
-
{
|
|
278
|
-
className: 'ide-tab-context-menu-item',
|
|
279
|
-
style: { padding: '6px 14px', cursor: 'pointer', color: '#ccc', fontSize: '12px', display: 'flex', alignItems: 'center', gap: '8px' },
|
|
280
|
-
onMouseEnter: function(e) { e.currentTarget.style.background = '#094771'; },
|
|
281
|
-
onMouseLeave: function(e) { e.currentTarget.style.background = 'transparent'; },
|
|
282
|
-
onClick: function() { setTabContextMenu(null); onCloseAll(); }
|
|
283
|
-
},
|
|
284
|
-
React.createElement('i', { className: 'fas fa-times', style: { width: '14px', textAlign: 'center' } }),
|
|
285
|
-
'Close All'
|
|
286
|
-
),
|
|
274
|
+
menuItem('fas fa-times', 'Close', function() { setTabContextMenu(null); onClose(tabContextMenu.tab.id); }),
|
|
275
|
+
onCloseOthers && menuItem('fas fa-times-circle', 'Close Others', function() { setTabContextMenu(null); onCloseOthers(tabContextMenu.tab.id); }),
|
|
276
|
+
onCloseSaved && menuItem('fas fa-check', 'Close Saved', function() { setTabContextMenu(null); onCloseSaved(); }),
|
|
277
|
+
onCloseAll && menuItem('fas fa-times', 'Close All', function() { setTabContextMenu(null); onCloseAll(); }),
|
|
287
278
|
React.createElement('div', { style: { height: '1px', background: '#454545', margin: '4px 0' } }),
|
|
288
|
-
onShowHistory &&
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
setTabContextMenu(null);
|
|
297
|
-
onShowHistory(tabContextMenu.tab.path);
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
React.createElement('i', { className: 'fas fa-history', style: { width: '14px', textAlign: 'center' } }),
|
|
301
|
-
'File History'
|
|
302
|
-
),
|
|
303
|
-
onRevealInExplorer && React.createElement(
|
|
304
|
-
'div',
|
|
305
|
-
{
|
|
306
|
-
className: 'ide-tab-context-menu-item',
|
|
307
|
-
style: { padding: '6px 14px', cursor: 'pointer', color: '#ccc', fontSize: '12px', display: 'flex', alignItems: 'center', gap: '8px' },
|
|
308
|
-
onMouseEnter: function(e) { e.currentTarget.style.background = '#094771'; },
|
|
309
|
-
onMouseLeave: function(e) { e.currentTarget.style.background = 'transparent'; },
|
|
310
|
-
onClick: function() {
|
|
311
|
-
setTabContextMenu(null);
|
|
312
|
-
onRevealInExplorer(tabContextMenu.tab.path);
|
|
313
|
-
}
|
|
314
|
-
},
|
|
315
|
-
React.createElement('i', { className: 'fas fa-sitemap', style: { width: '14px', textAlign: 'center' } }),
|
|
316
|
-
'Find in Explorer'
|
|
317
|
-
)
|
|
279
|
+
onShowHistory && menuItem('fas fa-history', 'File History', function() {
|
|
280
|
+
setTabContextMenu(null);
|
|
281
|
+
onShowHistory(tabContextMenu.tab.path);
|
|
282
|
+
}),
|
|
283
|
+
onRevealInExplorer && menuItem('fas fa-sitemap', 'Find in Explorer', function() {
|
|
284
|
+
setTabContextMenu(null);
|
|
285
|
+
onRevealInExplorer(tabContextMenu.tab.path);
|
|
286
|
+
})
|
|
318
287
|
)
|
|
319
288
|
);
|
|
320
289
|
};
|