mbeditor 0.1.6 → 0.1.7
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.
Potentially problematic release.
This version of mbeditor might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +30 -1
- data/app/assets/javascripts/mbeditor/application.js +1 -0
- data/app/assets/javascripts/mbeditor/components/DiffViewer.js +14 -2
- data/app/assets/javascripts/mbeditor/components/EditorPanel.js +228 -10
- data/app/assets/javascripts/mbeditor/components/FileHistoryPanel.js +6 -1
- data/app/assets/javascripts/mbeditor/components/FileTree.js +12 -1
- data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +226 -16
- data/app/assets/javascripts/mbeditor/components/TabBar.js +70 -1
- data/app/assets/javascripts/mbeditor/components/TestResultsPanel.js +150 -0
- data/app/assets/javascripts/mbeditor/file_service.js +5 -0
- data/app/assets/stylesheets/mbeditor/application.css +97 -11
- data/app/controllers/mbeditor/application_controller.rb +1 -1
- data/app/controllers/mbeditor/editors_controller.rb +45 -13
- data/app/controllers/mbeditor/git_controller.rb +13 -9
- data/app/services/mbeditor/git_diff_service.rb +3 -0
- data/app/services/mbeditor/git_service.rb +4 -2
- data/app/services/mbeditor/test_runner_service.rb +259 -0
- data/config/routes.rb +1 -0
- data/lib/mbeditor/configuration.rb +5 -1
- data/lib/mbeditor/rack/silence_ping_request.rb +13 -1
- data/lib/mbeditor/version.rb +1 -1
- metadata +4 -2
|
@@ -23,7 +23,14 @@ var DEFAULT_EDITOR_PREFS = {
|
|
|
23
23
|
fontSize: 13,
|
|
24
24
|
fontFamily: "'JetBrains Mono', 'Fira Code', Consolas, 'Courier New', monospace",
|
|
25
25
|
tabSize: 4,
|
|
26
|
-
insertSpaces: false
|
|
26
|
+
insertSpaces: false,
|
|
27
|
+
wordWrap: 'off',
|
|
28
|
+
lineNumbers: 'on',
|
|
29
|
+
renderWhitespace: 'none',
|
|
30
|
+
scrollBeyondLastLine: false,
|
|
31
|
+
minimap: false,
|
|
32
|
+
bracketPairColorization: true,
|
|
33
|
+
autoRevealInExplorer: true
|
|
27
34
|
};
|
|
28
35
|
|
|
29
36
|
var SidebarActionButton = function SidebarActionButton(_ref) {
|
|
@@ -260,6 +267,36 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
260
267
|
var redmineEnabled = _useState18f2[0];
|
|
261
268
|
var setRedmineEnabled = _useState18f2[1];
|
|
262
269
|
|
|
270
|
+
var _useState18t = useState(false);
|
|
271
|
+
var _useState18t2 = _slicedToArray(_useState18t, 2);
|
|
272
|
+
var testAvailable = _useState18t2[0];
|
|
273
|
+
var setTestAvailable = _useState18t2[1];
|
|
274
|
+
|
|
275
|
+
var _useState18u = useState(null);
|
|
276
|
+
var _useState18u2 = _slicedToArray(_useState18u, 2);
|
|
277
|
+
var testResult = _useState18u2[0];
|
|
278
|
+
var setTestResult = _useState18u2[1];
|
|
279
|
+
|
|
280
|
+
var _useState18v = useState(false);
|
|
281
|
+
var _useState18v2 = _slicedToArray(_useState18v, 2);
|
|
282
|
+
var testLoading = _useState18v2[0];
|
|
283
|
+
var setTestLoading = _useState18v2[1];
|
|
284
|
+
|
|
285
|
+
var _useState18w = useState(true);
|
|
286
|
+
var _useState18w2 = _slicedToArray(_useState18w, 2);
|
|
287
|
+
var testInlineVisible = _useState18w2[0];
|
|
288
|
+
var setTestInlineVisible = _useState18w2[1];
|
|
289
|
+
|
|
290
|
+
var _useState18x = useState(null);
|
|
291
|
+
var _useState18x2 = _slicedToArray(_useState18x, 2);
|
|
292
|
+
var testPanelFile = _useState18x2[0];
|
|
293
|
+
var setTestPanelFile = _useState18x2[1];
|
|
294
|
+
|
|
295
|
+
var _useState18y = useState(false);
|
|
296
|
+
var _useState18y2 = _slicedToArray(_useState18y, 2);
|
|
297
|
+
var testPanelOpen = _useState18y2[0];
|
|
298
|
+
var setTestPanelOpen = _useState18y2[1];
|
|
299
|
+
|
|
263
300
|
var _useState18p = useState(DEFAULT_EDITOR_PREFS);
|
|
264
301
|
var _useState18p2 = _slicedToArray(_useState18p, 2);
|
|
265
302
|
var editorPrefs = _useState18p2[0];
|
|
@@ -490,6 +527,9 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
490
527
|
if (workspace && typeof workspace.redmineEnabled === 'boolean') {
|
|
491
528
|
setRedmineEnabled(workspace.redmineEnabled);
|
|
492
529
|
}
|
|
530
|
+
if (workspace && typeof workspace.testAvailable === 'boolean') {
|
|
531
|
+
setTestAvailable(workspace.testAvailable);
|
|
532
|
+
}
|
|
493
533
|
});
|
|
494
534
|
GitService.fetchStatus();
|
|
495
535
|
|
|
@@ -499,11 +539,20 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
499
539
|
if (savedState && savedState.openTabs) {
|
|
500
540
|
panesToLoad = [{ id: 1, tabs: savedState.openTabs, activeTabId: savedState.activeTabId }, { id: 2, tabs: [], activeTabId: null }];
|
|
501
541
|
}
|
|
542
|
+
if (savedState && savedState.editorPrefs && typeof savedState.editorPrefs === 'object') {
|
|
543
|
+
setEditorPrefs(Object.assign({}, DEFAULT_EDITOR_PREFS, savedState.editorPrefs));
|
|
544
|
+
}
|
|
545
|
+
if (savedState && savedState.activeSidebarTab) {
|
|
546
|
+
setActiveSidebarTab(savedState.activeSidebarTab);
|
|
547
|
+
}
|
|
502
548
|
if (panesToLoad && panesToLoad.length > 0) {
|
|
503
549
|
var allTabs = panesToLoad.flatMap(function (p) {
|
|
504
550
|
return p.tabs;
|
|
505
551
|
});
|
|
506
552
|
Promise.all(allTabs.map(function (t) {
|
|
553
|
+
if (t.isSettings || t.path === '__settings__') {
|
|
554
|
+
return Promise.resolve({ content: '' });
|
|
555
|
+
}
|
|
507
556
|
if (t.isDiff && t.repoPath) {
|
|
508
557
|
return GitService.fetchDiff(t.repoPath, t.diffBaseSha, t.diffHeadSha)
|
|
509
558
|
.then(function (d) { return { content: 'Diff loaded', diffOriginal: d.original || '', diffModified: d.modified || '', _isDiffResult: true }; })
|
|
@@ -543,9 +592,6 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
543
592
|
if (typeof savedState.gitPanelWidth === 'number') {
|
|
544
593
|
setGitPanelWidth(savedState.gitPanelWidth);
|
|
545
594
|
}
|
|
546
|
-
if (savedState.editorPrefs && typeof savedState.editorPrefs === 'object') {
|
|
547
|
-
setEditorPrefs(Object.assign({}, DEFAULT_EDITOR_PREFS, savedState.editorPrefs));
|
|
548
|
-
}
|
|
549
595
|
});
|
|
550
596
|
}
|
|
551
597
|
});
|
|
@@ -827,13 +873,14 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
827
873
|
return {
|
|
828
874
|
id: p.id,
|
|
829
875
|
activeTabId: p.activeTabId,
|
|
830
|
-
tabs: p.tabs.filter(function(t) { return !t.isCombinedDiff
|
|
876
|
+
tabs: p.tabs.filter(function(t) { return !t.isCombinedDiff; }).map(function (t) {
|
|
831
877
|
return {
|
|
832
878
|
id: t.id,
|
|
833
879
|
path: t.path,
|
|
834
880
|
name: t.name,
|
|
835
881
|
dirty: t.dirty,
|
|
836
882
|
viewState: t.viewState,
|
|
883
|
+
isSettings: !!t.isSettings,
|
|
837
884
|
isPreview: !!t.isPreview,
|
|
838
885
|
previewFor: t.previewFor || null,
|
|
839
886
|
isDiff: !!t.isDiff,
|
|
@@ -844,12 +891,12 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
844
891
|
})
|
|
845
892
|
};
|
|
846
893
|
});
|
|
847
|
-
FileService.saveState({ panes: lightweightPanes, focusedPaneId: st.focusedPaneId, collapsedSections: collapsedSections, expandedDirs: expandedDirs, showGitPanel: showGitPanel, gitPanelWidth: gitPanelWidth, editorPrefs: editorPrefs });
|
|
894
|
+
FileService.saveState({ panes: lightweightPanes, focusedPaneId: st.focusedPaneId, collapsedSections: collapsedSections, expandedDirs: expandedDirs, showGitPanel: showGitPanel, gitPanelWidth: gitPanelWidth, editorPrefs: editorPrefs, activeSidebarTab: activeSidebarTab });
|
|
848
895
|
}, 1000);
|
|
849
896
|
return function () {
|
|
850
897
|
return clearTimeout(timeoutId);
|
|
851
898
|
};
|
|
852
|
-
}, [state.panes, state.focusedPaneId, collapsedSections, expandedDirs, showGitPanel, gitPanelWidth, editorPrefs]);
|
|
899
|
+
}, [state.panes, state.focusedPaneId, collapsedSections, expandedDirs, showGitPanel, gitPanelWidth, editorPrefs, activeSidebarTab]);
|
|
853
900
|
|
|
854
901
|
useEffect(function() {
|
|
855
902
|
document.documentElement.setAttribute('data-theme', editorPrefs.theme || 'vs-dark');
|
|
@@ -1113,6 +1160,39 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
1113
1160
|
}
|
|
1114
1161
|
};
|
|
1115
1162
|
|
|
1163
|
+
var handleRunTest = function handleRunTest() {
|
|
1164
|
+
if (!activeTab || !activeTab.path) return;
|
|
1165
|
+
if (testLoading) return;
|
|
1166
|
+
|
|
1167
|
+
setTestLoading(true);
|
|
1168
|
+
EditorStore.setStatus('Running tests...', 'info');
|
|
1169
|
+
|
|
1170
|
+
FileService.runTests(activeTab.path).then(function (res) {
|
|
1171
|
+
setTestResult(res);
|
|
1172
|
+
setTestPanelFile(res.testFile || activeTab.path);
|
|
1173
|
+
setTestPanelOpen(true);
|
|
1174
|
+
if (res.ok) {
|
|
1175
|
+
var s = res.summary || {};
|
|
1176
|
+
var failCount = (s.failed || 0) + (s.errored || 0);
|
|
1177
|
+
if (failCount === 0) {
|
|
1178
|
+
EditorStore.setStatus('All ' + (s.total || 0) + ' tests passed', 'success');
|
|
1179
|
+
} else {
|
|
1180
|
+
EditorStore.setStatus(failCount + ' test' + (failCount === 1 ? '' : 's') + ' failed out of ' + (s.total || 0), 'warning');
|
|
1181
|
+
}
|
|
1182
|
+
} else {
|
|
1183
|
+
EditorStore.setStatus('Test run failed: ' + (res.error || 'unknown error'), 'error');
|
|
1184
|
+
}
|
|
1185
|
+
})["catch"](function (err) {
|
|
1186
|
+
var msg = err.response && err.response.data && err.response.data.error || err.message;
|
|
1187
|
+
setTestResult({ ok: false, error: msg, tests: [], summary: null });
|
|
1188
|
+
setTestPanelFile(activeTab.path);
|
|
1189
|
+
setTestPanelOpen(true);
|
|
1190
|
+
EditorStore.setStatus('Test run failed: ' + msg, 'error');
|
|
1191
|
+
})["finally"](function () {
|
|
1192
|
+
setTestLoading(false);
|
|
1193
|
+
});
|
|
1194
|
+
};
|
|
1195
|
+
|
|
1116
1196
|
var onFormatRef = useRef(handleFormat);
|
|
1117
1197
|
onFormatRef.current = handleFormat;
|
|
1118
1198
|
|
|
@@ -1555,6 +1635,18 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
1555
1635
|
},
|
|
1556
1636
|
onShowHistory: function (path) {
|
|
1557
1637
|
setHistoryPanelPath(path);
|
|
1638
|
+
},
|
|
1639
|
+
onRevealInExplorer: function (path) {
|
|
1640
|
+
setActiveSidebarTab('explorer');
|
|
1641
|
+
setSelectedTreeNode({ path: path, name: path.split('/').pop(), type: 'file' });
|
|
1642
|
+
setExpandedDirs(function (prev) {
|
|
1643
|
+
var parts = path.split('/');
|
|
1644
|
+
var updates = {};
|
|
1645
|
+
for (var i = 0; i < parts.length - 1; i++) {
|
|
1646
|
+
updates[parts.slice(0, i + 1).join('/')] = true;
|
|
1647
|
+
}
|
|
1648
|
+
return Object.assign({}, prev, updates);
|
|
1649
|
+
});
|
|
1558
1650
|
}
|
|
1559
1651
|
});
|
|
1560
1652
|
};
|
|
@@ -1847,7 +1939,7 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
1847
1939
|
React.createElement(FileTree, {
|
|
1848
1940
|
items: treeData,
|
|
1849
1941
|
onSelect: handleSoftOpenFile,
|
|
1850
|
-
activePath: activeTab && activeTab.path,
|
|
1942
|
+
activePath: editorPrefs.autoRevealInExplorer !== false ? (activeTab && activeTab.path) : null,
|
|
1851
1943
|
selectedPath: selectedTreePath,
|
|
1852
1944
|
onNodeSelect: setSelectedTreeNode,
|
|
1853
1945
|
gitFiles: state.gitFiles,
|
|
@@ -2079,7 +2171,7 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
2079
2171
|
type: 'checkbox',
|
|
2080
2172
|
className: 'ide-settings-checkbox',
|
|
2081
2173
|
checked: !!(editorPrefs.insertSpaces),
|
|
2082
|
-
onChange: function(e) { setEditorPrefs(function(p) { return Object.assign({}, p, { insertSpaces:
|
|
2174
|
+
onChange: function(e) { var v = e.target.checked; setEditorPrefs(function(p) { return Object.assign({}, p, { insertSpaces: v }); }); }
|
|
2083
2175
|
})
|
|
2084
2176
|
),
|
|
2085
2177
|
React.createElement(
|
|
@@ -2092,6 +2184,89 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
2092
2184
|
onChange: function(e) { setEditorPrefs(function(p) { return Object.assign({}, p, { fontFamily: e.target.value }); }); }
|
|
2093
2185
|
})
|
|
2094
2186
|
),
|
|
2187
|
+
React.createElement(
|
|
2188
|
+
'label', { className: 'ide-settings-row' },
|
|
2189
|
+
React.createElement('span', { className: 'ide-settings-label' }, 'Word wrap'),
|
|
2190
|
+
React.createElement(
|
|
2191
|
+
'select', {
|
|
2192
|
+
className: 'ide-settings-select',
|
|
2193
|
+
value: editorPrefs.wordWrap || 'off',
|
|
2194
|
+
onChange: function(e) { setEditorPrefs(function(p) { return Object.assign({}, p, { wordWrap: e.target.value }); }); }
|
|
2195
|
+
},
|
|
2196
|
+
React.createElement('option', { value: 'off' }, 'Off'),
|
|
2197
|
+
React.createElement('option', { value: 'on' }, 'On'),
|
|
2198
|
+
React.createElement('option', { value: 'wordWrapColumn' }, 'Column')
|
|
2199
|
+
)
|
|
2200
|
+
),
|
|
2201
|
+
React.createElement(
|
|
2202
|
+
'label', { className: 'ide-settings-row' },
|
|
2203
|
+
React.createElement('span', { className: 'ide-settings-label' }, 'Line numbers'),
|
|
2204
|
+
React.createElement(
|
|
2205
|
+
'select', {
|
|
2206
|
+
className: 'ide-settings-select',
|
|
2207
|
+
value: editorPrefs.lineNumbers || 'on',
|
|
2208
|
+
onChange: function(e) { setEditorPrefs(function(p) { return Object.assign({}, p, { lineNumbers: e.target.value }); }); }
|
|
2209
|
+
},
|
|
2210
|
+
React.createElement('option', { value: 'on' }, 'On'),
|
|
2211
|
+
React.createElement('option', { value: 'off' }, 'Off'),
|
|
2212
|
+
React.createElement('option', { value: 'relative' }, 'Relative')
|
|
2213
|
+
)
|
|
2214
|
+
),
|
|
2215
|
+
React.createElement(
|
|
2216
|
+
'label', { className: 'ide-settings-row' },
|
|
2217
|
+
React.createElement('span', { className: 'ide-settings-label' }, 'Render whitespace'),
|
|
2218
|
+
React.createElement(
|
|
2219
|
+
'select', {
|
|
2220
|
+
className: 'ide-settings-select',
|
|
2221
|
+
value: editorPrefs.renderWhitespace || 'none',
|
|
2222
|
+
onChange: function(e) { setEditorPrefs(function(p) { return Object.assign({}, p, { renderWhitespace: e.target.value }); }); }
|
|
2223
|
+
},
|
|
2224
|
+
React.createElement('option', { value: 'none' }, 'None'),
|
|
2225
|
+
React.createElement('option', { value: 'selection' }, 'Selection only'),
|
|
2226
|
+
React.createElement('option', { value: 'boundary' }, 'Boundary'),
|
|
2227
|
+
React.createElement('option', { value: 'all' }, 'All')
|
|
2228
|
+
)
|
|
2229
|
+
),
|
|
2230
|
+
React.createElement(
|
|
2231
|
+
'label', { className: 'ide-settings-row ide-settings-row-check' },
|
|
2232
|
+
React.createElement('span', { className: 'ide-settings-label' }, 'Minimap'),
|
|
2233
|
+
React.createElement('input', {
|
|
2234
|
+
type: 'checkbox',
|
|
2235
|
+
className: 'ide-settings-checkbox',
|
|
2236
|
+
checked: !!(editorPrefs.minimap),
|
|
2237
|
+
onChange: function(e) { var v = e.target.checked; setEditorPrefs(function(p) { return Object.assign({}, p, { minimap: v }); }); }
|
|
2238
|
+
})
|
|
2239
|
+
),
|
|
2240
|
+
React.createElement(
|
|
2241
|
+
'label', { className: 'ide-settings-row ide-settings-row-check' },
|
|
2242
|
+
React.createElement('span', { className: 'ide-settings-label' }, 'Scroll beyond last line'),
|
|
2243
|
+
React.createElement('input', {
|
|
2244
|
+
type: 'checkbox',
|
|
2245
|
+
className: 'ide-settings-checkbox',
|
|
2246
|
+
checked: !!(editorPrefs.scrollBeyondLastLine),
|
|
2247
|
+
onChange: function(e) { var v = e.target.checked; setEditorPrefs(function(p) { return Object.assign({}, p, { scrollBeyondLastLine: v }); }); }
|
|
2248
|
+
})
|
|
2249
|
+
),
|
|
2250
|
+
React.createElement(
|
|
2251
|
+
'label', { className: 'ide-settings-row ide-settings-row-check' },
|
|
2252
|
+
React.createElement('span', { className: 'ide-settings-label' }, 'Bracket colorization'),
|
|
2253
|
+
React.createElement('input', {
|
|
2254
|
+
type: 'checkbox',
|
|
2255
|
+
className: 'ide-settings-checkbox',
|
|
2256
|
+
checked: !!(editorPrefs.bracketPairColorization),
|
|
2257
|
+
onChange: function(e) { var v = e.target.checked; setEditorPrefs(function(p) { return Object.assign({}, p, { bracketPairColorization: v }); }); }
|
|
2258
|
+
})
|
|
2259
|
+
),
|
|
2260
|
+
React.createElement(
|
|
2261
|
+
'label', { className: 'ide-settings-row ide-settings-row-check' },
|
|
2262
|
+
React.createElement('span', { className: 'ide-settings-label' }, 'Explorer follows active file'),
|
|
2263
|
+
React.createElement('input', {
|
|
2264
|
+
type: 'checkbox',
|
|
2265
|
+
className: 'ide-settings-checkbox',
|
|
2266
|
+
checked: !!(editorPrefs.autoRevealInExplorer),
|
|
2267
|
+
onChange: function(e) { var v = e.target.checked; setEditorPrefs(function(p) { return Object.assign({}, p, { autoRevealInExplorer: v }); }); }
|
|
2268
|
+
})
|
|
2269
|
+
),
|
|
2095
2270
|
React.createElement(
|
|
2096
2271
|
'button',
|
|
2097
2272
|
{
|
|
@@ -2112,6 +2287,7 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
2112
2287
|
original: pActiveTab.diffOriginal || '',
|
|
2113
2288
|
modified: pActiveTab.diffModified || '',
|
|
2114
2289
|
isDark: isDiffDark,
|
|
2290
|
+
editorPrefs: editorPrefs,
|
|
2115
2291
|
onClose: function() { requestCloseTab(pane.id, pActiveTab.id); }
|
|
2116
2292
|
});
|
|
2117
2293
|
} else {
|
|
@@ -2121,8 +2297,15 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
2121
2297
|
paneId: pane.id,
|
|
2122
2298
|
markers: markers[pActiveTab.id] || [],
|
|
2123
2299
|
gitAvailable: gitAvailable,
|
|
2300
|
+
testAvailable: testAvailable,
|
|
2301
|
+
testResult: testResult,
|
|
2302
|
+
testPanelFile: testPanelFile,
|
|
2303
|
+
testLoading: testLoading,
|
|
2304
|
+
testInlineVisible: testInlineVisible,
|
|
2124
2305
|
editorPrefs: editorPrefs,
|
|
2125
2306
|
onFormat: function() { onFormatRef.current(); },
|
|
2307
|
+
onRunTest: handleRunTest,
|
|
2308
|
+
onShowHistory: function(path) { setHistoryPanelPath(path); },
|
|
2126
2309
|
onContentChange: function onContentChange(val) {
|
|
2127
2310
|
var st = EditorStore.getState();
|
|
2128
2311
|
var cp = st.panes.find(function(p) { return p.id === pane.id; });
|
|
@@ -2151,7 +2334,11 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
2151
2334
|
{
|
|
2152
2335
|
className: "ide-pane " + (isFocused ? 'focused' : '') + " " + (isDropTarget ? 'drop-target' : ''),
|
|
2153
2336
|
style: { flexBasis: flexBasis, flexShrink: 0, flexGrow: 0, display: 'flex', flexDirection: 'column', minWidth: 0 },
|
|
2154
|
-
onClickCapture: function () {
|
|
2337
|
+
onClickCapture: function (e) {
|
|
2338
|
+
// Do not steal click events from controls inside the Settings tab.
|
|
2339
|
+
// Focusing the pane in capture phase can rerender before checkbox
|
|
2340
|
+
// change events are processed, making toggles appear stuck.
|
|
2341
|
+
if (e.target && e.target.closest && e.target.closest('.ide-settings-tab-content')) return;
|
|
2155
2342
|
return TabManager.focusPane(pane.id);
|
|
2156
2343
|
},
|
|
2157
2344
|
onDragOver: function (e) {
|
|
@@ -2357,12 +2544,35 @@ var MbeditorApp = function MbeditorApp() {
|
|
|
2357
2544
|
),
|
|
2358
2545
|
|
|
2359
2546
|
// File History Panel overlay
|
|
2360
|
-
historyPanelPath && React.createElement(
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2547
|
+
historyPanelPath && React.createElement(
|
|
2548
|
+
React.Fragment,
|
|
2549
|
+
null,
|
|
2550
|
+
React.createElement("div", {
|
|
2551
|
+
style: { position: 'fixed', inset: 0, zIndex: 9800, background: 'rgba(0,0,0,0.55)' },
|
|
2552
|
+
onClick: function() { setHistoryPanelPath(null); }
|
|
2553
|
+
}),
|
|
2554
|
+
React.createElement(window.FileHistoryPanel || FileHistoryPanel, {
|
|
2555
|
+
path: historyPanelPath,
|
|
2556
|
+
onClose: function () { return setHistoryPanelPath(null); },
|
|
2557
|
+
onSelectCommit: function (hash, path) {
|
|
2558
|
+
TabManager.openDiffTab(path, path.split('/').pop(), hash + '^', hash, null);
|
|
2559
|
+
}
|
|
2560
|
+
})
|
|
2561
|
+
),
|
|
2562
|
+
|
|
2563
|
+
// Test Results Panel overlay — closing hides the dialog but keeps testResult for inline markers
|
|
2564
|
+
(testPanelOpen || testLoading) && React.createElement(window.TestResultsPanel || TestResultsPanel, {
|
|
2565
|
+
result: testResult,
|
|
2566
|
+
testFile: testPanelFile,
|
|
2567
|
+
isLoading: testLoading,
|
|
2568
|
+
showInline: testInlineVisible,
|
|
2569
|
+
onToggleInline: function () { setTestInlineVisible(function (prev) { return !prev; }); },
|
|
2570
|
+
onClose: function () { setTestPanelOpen(false); },
|
|
2571
|
+
onOpenTestFile: testPanelFile ? function () {
|
|
2572
|
+
var fileName = testPanelFile.split('/').pop();
|
|
2573
|
+
TabManager.openTab(testPanelFile, fileName);
|
|
2574
|
+
setTestPanelOpen(false);
|
|
2575
|
+
} : null
|
|
2366
2576
|
}),
|
|
2367
2577
|
|
|
2368
2578
|
// Commit Detail overlay (shown when a commit row is clicked in CommitGraph)
|
|
@@ -16,6 +16,7 @@ var TabBar = function TabBar(_ref) {
|
|
|
16
16
|
var onTabDragEnd = _ref.onTabDragEnd;
|
|
17
17
|
var onHardenTab = _ref.onHardenTab;
|
|
18
18
|
var onShowHistory = _ref.onShowHistory;
|
|
19
|
+
var onRevealInExplorer = _ref.onRevealInExplorer;
|
|
19
20
|
|
|
20
21
|
var containerRef = useRef(null);
|
|
21
22
|
|
|
@@ -26,6 +27,13 @@ var TabBar = function TabBar(_ref) {
|
|
|
26
27
|
var draggingTabId = _useState2[0];
|
|
27
28
|
var setDraggingTabId = _useState2[1];
|
|
28
29
|
|
|
30
|
+
var _useState3 = useState(null);
|
|
31
|
+
|
|
32
|
+
var _useState4 = _slicedToArray(_useState3, 2);
|
|
33
|
+
|
|
34
|
+
var tabContextMenu = _useState4[0];
|
|
35
|
+
var setTabContextMenu = _useState4[1];
|
|
36
|
+
|
|
29
37
|
var getTabMarkerClass = function getTabMarkerClass(tab) {
|
|
30
38
|
var tabMarkers = tab.markers || [];
|
|
31
39
|
if (!tabMarkers.length) return '';
|
|
@@ -55,7 +63,18 @@ var TabBar = function TabBar(_ref) {
|
|
|
55
63
|
}
|
|
56
64
|
}, [activeId, tabs]);
|
|
57
65
|
|
|
66
|
+
// Close context menu on outside click (bubble phase so onMouseDown on the menu can stop it)
|
|
67
|
+
useEffect(function () {
|
|
68
|
+
if (!tabContextMenu) return;
|
|
69
|
+
var handler = function () { setTabContextMenu(null); };
|
|
70
|
+
document.addEventListener('mousedown', handler);
|
|
71
|
+
return function () { document.removeEventListener('mousedown', handler); };
|
|
72
|
+
}, [tabContextMenu]);
|
|
73
|
+
|
|
58
74
|
return React.createElement(
|
|
75
|
+
React.Fragment,
|
|
76
|
+
null,
|
|
77
|
+
React.createElement(
|
|
59
78
|
'div',
|
|
60
79
|
{ className: 'tab-bar', ref: containerRef, onWheel: function (e) {
|
|
61
80
|
if (containerRef.current) {
|
|
@@ -90,7 +109,7 @@ var TabBar = function TabBar(_ref) {
|
|
|
90
109
|
onContextMenu: function (e) {
|
|
91
110
|
if (isSpecial) return;
|
|
92
111
|
e.preventDefault();
|
|
93
|
-
|
|
112
|
+
setTabContextMenu({ x: e.clientX, y: e.clientY, tab: tab });
|
|
94
113
|
}
|
|
95
114
|
},
|
|
96
115
|
React.createElement('i', { className: 'tab-item-icon ' + (tab.isSettings ? 'fas fa-cog' : (window.getFileIcon ? window.getFileIcon(tab.name) : 'far fa-file-code')) }),
|
|
@@ -117,6 +136,56 @@ var TabBar = function TabBar(_ref) {
|
|
|
117
136
|
)
|
|
118
137
|
);
|
|
119
138
|
})
|
|
139
|
+
),
|
|
140
|
+
tabContextMenu && React.createElement(
|
|
141
|
+
'div',
|
|
142
|
+
{
|
|
143
|
+
className: 'ide-tab-context-menu',
|
|
144
|
+
style: {
|
|
145
|
+
position: 'fixed',
|
|
146
|
+
top: tabContextMenu.y,
|
|
147
|
+
left: tabContextMenu.x,
|
|
148
|
+
zIndex: 9999,
|
|
149
|
+
background: '#252526',
|
|
150
|
+
border: '1px solid #454545',
|
|
151
|
+
borderRadius: '4px',
|
|
152
|
+
boxShadow: '0 4px 12px rgba(0,0,0,0.5)',
|
|
153
|
+
minWidth: '160px',
|
|
154
|
+
padding: '4px 0'
|
|
155
|
+
},
|
|
156
|
+
onMouseDown: function(e) { e.stopPropagation(); }
|
|
157
|
+
},
|
|
158
|
+
onShowHistory && React.createElement(
|
|
159
|
+
'div',
|
|
160
|
+
{
|
|
161
|
+
className: 'ide-tab-context-menu-item',
|
|
162
|
+
style: { padding: '6px 14px', cursor: 'pointer', color: '#ccc', fontSize: '12px', display: 'flex', alignItems: 'center', gap: '8px' },
|
|
163
|
+
onMouseEnter: function(e) { e.currentTarget.style.background = '#094771'; },
|
|
164
|
+
onMouseLeave: function(e) { e.currentTarget.style.background = 'transparent'; },
|
|
165
|
+
onClick: function() {
|
|
166
|
+
setTabContextMenu(null);
|
|
167
|
+
onShowHistory(tabContextMenu.tab.path);
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
React.createElement('i', { className: 'fas fa-history', style: { width: '14px', textAlign: 'center' } }),
|
|
171
|
+
'File History'
|
|
172
|
+
),
|
|
173
|
+
onRevealInExplorer && React.createElement(
|
|
174
|
+
'div',
|
|
175
|
+
{
|
|
176
|
+
className: 'ide-tab-context-menu-item',
|
|
177
|
+
style: { padding: '6px 14px', cursor: 'pointer', color: '#ccc', fontSize: '12px', display: 'flex', alignItems: 'center', gap: '8px' },
|
|
178
|
+
onMouseEnter: function(e) { e.currentTarget.style.background = '#094771'; },
|
|
179
|
+
onMouseLeave: function(e) { e.currentTarget.style.background = 'transparent'; },
|
|
180
|
+
onClick: function() {
|
|
181
|
+
setTabContextMenu(null);
|
|
182
|
+
onRevealInExplorer(tabContextMenu.tab.path);
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
React.createElement('i', { className: 'fas fa-sitemap', style: { width: '14px', textAlign: 'center' } }),
|
|
186
|
+
'Find in Explorer'
|
|
187
|
+
)
|
|
188
|
+
)
|
|
120
189
|
);
|
|
121
190
|
};
|
|
122
191
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var TestResultsPanel = function TestResultsPanel(_ref) {
|
|
4
|
+
var result = _ref.result;
|
|
5
|
+
var testFile = _ref.testFile;
|
|
6
|
+
var isLoading = _ref.isLoading;
|
|
7
|
+
var onClose = _ref.onClose;
|
|
8
|
+
var showInline = _ref.showInline;
|
|
9
|
+
var onToggleInline = _ref.onToggleInline;
|
|
10
|
+
var onOpenTestFile = _ref.onOpenTestFile;
|
|
11
|
+
|
|
12
|
+
if (!result && !isLoading) return null;
|
|
13
|
+
|
|
14
|
+
var summary = result && result.summary;
|
|
15
|
+
var tests = result && result.tests || [];
|
|
16
|
+
var error = result && result.error;
|
|
17
|
+
|
|
18
|
+
var statusIcon = function statusIcon(status) {
|
|
19
|
+
if (status === 'pass') return React.createElement('i', { className: 'fas fa-check-circle', style: { color: '#4ec9b0', marginRight: '6px' } });
|
|
20
|
+
if (status === 'fail') return React.createElement('i', { className: 'fas fa-times-circle', style: { color: '#f14c4c', marginRight: '6px' } });
|
|
21
|
+
if (status === 'error') return React.createElement('i', { className: 'fas fa-exclamation-circle', style: { color: '#cca700', marginRight: '6px' } });
|
|
22
|
+
if (status === 'skip') return React.createElement('i', { className: 'fas fa-forward', style: { color: '#888', marginRight: '6px' } });
|
|
23
|
+
return React.createElement('i', { className: 'fas fa-circle', style: { color: '#888', marginRight: '6px' } });
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
return React.createElement(
|
|
27
|
+
React.Fragment,
|
|
28
|
+
null,
|
|
29
|
+
React.createElement('div', { className: 'ide-modal-backdrop', onClick: onClose }),
|
|
30
|
+
React.createElement(
|
|
31
|
+
'div',
|
|
32
|
+
{ className: 'ide-modal-panel' },
|
|
33
|
+
React.createElement(
|
|
34
|
+
'div',
|
|
35
|
+
{ className: 'ide-file-history-header' },
|
|
36
|
+
React.createElement(
|
|
37
|
+
'div',
|
|
38
|
+
{ className: 'ide-file-history-title' },
|
|
39
|
+
React.createElement('i', { className: 'fas fa-flask' }),
|
|
40
|
+
React.createElement(
|
|
41
|
+
'span',
|
|
42
|
+
null,
|
|
43
|
+
'Tests: ',
|
|
44
|
+
testFile ? testFile.split('/').pop() : 'Results'
|
|
45
|
+
)
|
|
46
|
+
),
|
|
47
|
+
React.createElement(
|
|
48
|
+
'div',
|
|
49
|
+
{ style: { display: 'flex', alignItems: 'center', gap: '6px' } },
|
|
50
|
+
onToggleInline && React.createElement(
|
|
51
|
+
'button',
|
|
52
|
+
{
|
|
53
|
+
className: 'ide-icon-btn' + (showInline ? ' active' : ''),
|
|
54
|
+
onClick: onToggleInline,
|
|
55
|
+
title: showInline ? 'Hide inline markers' : 'Show inline markers',
|
|
56
|
+
style: { fontSize: '11px', padding: '2px 5px', opacity: showInline ? 1 : 0.6, background: showInline ? 'rgba(255,255,255,0.1)' : 'transparent', border: 'none', color: '#ccc', cursor: 'pointer', borderRadius: '3px' }
|
|
57
|
+
},
|
|
58
|
+
React.createElement('i', { className: 'fas fa-map-marker-alt' })
|
|
59
|
+
),
|
|
60
|
+
onOpenTestFile && React.createElement(
|
|
61
|
+
'button',
|
|
62
|
+
{
|
|
63
|
+
className: 'ide-icon-btn',
|
|
64
|
+
onClick: onOpenTestFile,
|
|
65
|
+
title: 'Open test file',
|
|
66
|
+
style: { fontSize: '11px', padding: '2px 5px', background: 'transparent', border: 'none', color: '#ccc', cursor: 'pointer', borderRadius: '3px' }
|
|
67
|
+
},
|
|
68
|
+
React.createElement('i', { className: 'fas fa-external-link-alt', style: { marginRight: '4px' } }),
|
|
69
|
+
'Open Test File'
|
|
70
|
+
),
|
|
71
|
+
React.createElement(
|
|
72
|
+
'button',
|
|
73
|
+
{ className: 'ide-icon-btn', onClick: onClose, title: 'Close Test Results' },
|
|
74
|
+
React.createElement('i', { className: 'fas fa-times' })
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
),
|
|
78
|
+
React.createElement(
|
|
79
|
+
'div',
|
|
80
|
+
{ className: 'ide-file-history-content' },
|
|
81
|
+
isLoading ? React.createElement(
|
|
82
|
+
'div',
|
|
83
|
+
{ className: 'ide-loading-state' },
|
|
84
|
+
React.createElement('i', { className: 'fas fa-spinner fa-spin' }),
|
|
85
|
+
' Running tests...'
|
|
86
|
+
) : error ? React.createElement(
|
|
87
|
+
'div',
|
|
88
|
+
{ className: 'ide-error-state' },
|
|
89
|
+
error
|
|
90
|
+
) : !summary ? React.createElement(
|
|
91
|
+
'div',
|
|
92
|
+
{ className: 'ide-empty-state' },
|
|
93
|
+
'No test results.'
|
|
94
|
+
) : React.createElement(
|
|
95
|
+
'div',
|
|
96
|
+
null,
|
|
97
|
+
React.createElement(
|
|
98
|
+
'div',
|
|
99
|
+
{ style: { padding: '8px 12px', borderBottom: '1px solid #3c3c3c', fontSize: '12px', color: '#ccc', display: 'flex', gap: '12px', flexWrap: 'wrap' } },
|
|
100
|
+
React.createElement('span', null, React.createElement('strong', null, summary.total), ' total'),
|
|
101
|
+
summary.passed > 0 && React.createElement('span', { style: { color: '#4ec9b0' } }, React.createElement('i', { className: 'fas fa-check-circle', style: { marginRight: '3px' } }), summary.passed, ' passed'),
|
|
102
|
+
summary.failed > 0 && React.createElement('span', { style: { color: '#f14c4c' } }, React.createElement('i', { className: 'fas fa-times-circle', style: { marginRight: '3px' } }), summary.failed, ' failed'),
|
|
103
|
+
summary.errored > 0 && React.createElement('span', { style: { color: '#cca700' } }, React.createElement('i', { className: 'fas fa-exclamation-circle', style: { marginRight: '3px' } }), summary.errored, ' errors'),
|
|
104
|
+
summary.skipped > 0 && React.createElement('span', { style: { color: '#888' } }, summary.skipped, ' skipped'),
|
|
105
|
+
summary.duration != null && React.createElement('span', { style: { color: '#888' } }, summary.duration, 's')
|
|
106
|
+
),
|
|
107
|
+
tests.length > 0 ? React.createElement(
|
|
108
|
+
'div',
|
|
109
|
+
{ className: 'git-list' },
|
|
110
|
+
tests.map(function (t, i) {
|
|
111
|
+
return React.createElement(
|
|
112
|
+
'div',
|
|
113
|
+
{ key: i, className: 'git-commit-item', style: { cursor: 'default' } },
|
|
114
|
+
React.createElement(
|
|
115
|
+
'div',
|
|
116
|
+
{ className: 'git-commit-title', style: { display: 'flex', alignItems: 'center' } },
|
|
117
|
+
statusIcon(t.status),
|
|
118
|
+
React.createElement('span', { title: t.name }, t.name)
|
|
119
|
+
),
|
|
120
|
+
t.message && React.createElement(
|
|
121
|
+
'div',
|
|
122
|
+
{ className: 'git-commit-meta', style: { color: '#f14c4c', whiteSpace: 'pre-wrap', fontFamily: 'monospace', fontSize: '11px', marginTop: '4px', maxHeight: '120px', overflow: 'auto' } },
|
|
123
|
+
t.message
|
|
124
|
+
),
|
|
125
|
+
t.line && React.createElement(
|
|
126
|
+
'div',
|
|
127
|
+
{ className: 'git-commit-meta' },
|
|
128
|
+
'Line ',
|
|
129
|
+
t.line
|
|
130
|
+
)
|
|
131
|
+
);
|
|
132
|
+
})
|
|
133
|
+
) : React.createElement(
|
|
134
|
+
'div',
|
|
135
|
+
{ style: { padding: '8px 12px', fontSize: '12px', color: '#888' } },
|
|
136
|
+
summary.total > 0 ? 'All tests passed.' : 'No test details available. Check raw output.'
|
|
137
|
+
),
|
|
138
|
+
result && result.raw && tests.length === 0 && React.createElement(
|
|
139
|
+
'details',
|
|
140
|
+
{ style: { padding: '8px 12px' } },
|
|
141
|
+
React.createElement('summary', { style: { cursor: 'pointer', color: '#888', fontSize: '11px' } }, 'Raw output'),
|
|
142
|
+
React.createElement('pre', { style: { fontSize: '11px', color: '#ccc', whiteSpace: 'pre-wrap', maxHeight: '300px', overflow: 'auto', marginTop: '6px' } }, result.raw)
|
|
143
|
+
)
|
|
144
|
+
)
|
|
145
|
+
)
|
|
146
|
+
)
|
|
147
|
+
);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
window.TestResultsPanel = TestResultsPanel;
|
|
@@ -51,6 +51,10 @@ var FileService = (function () {
|
|
|
51
51
|
return axios.post(basePath() + '/format', { path: path }).then(function(res) { return res.data; });
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
function runTests(path) {
|
|
55
|
+
return axios.post(basePath() + '/test', { path: path }).then(function(res) { return res.data; });
|
|
56
|
+
}
|
|
57
|
+
|
|
54
58
|
function ping() {
|
|
55
59
|
return axios.get(basePath() + '/ping', { timeout: 4000 }).then(function(res) { return res.data; });
|
|
56
60
|
}
|
|
@@ -75,6 +79,7 @@ var FileService = (function () {
|
|
|
75
79
|
lintFile: lintFile,
|
|
76
80
|
quickFixOffense: quickFixOffense,
|
|
77
81
|
formatFile: formatFile,
|
|
82
|
+
runTests: runTests,
|
|
78
83
|
ping: ping,
|
|
79
84
|
getState: getState,
|
|
80
85
|
saveState: saveState
|