mbeditor 0.1.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 +7 -0
- data/README.md +127 -0
- data/app/assets/javascripts/mbeditor/application.js +19 -0
- data/app/assets/javascripts/mbeditor/components/CodeReviewPanel.js +202 -0
- data/app/assets/javascripts/mbeditor/components/CollapsibleSection.js +71 -0
- data/app/assets/javascripts/mbeditor/components/CombinedDiffViewer.js +139 -0
- data/app/assets/javascripts/mbeditor/components/CommitGraph.js +65 -0
- data/app/assets/javascripts/mbeditor/components/DiffViewer.js +142 -0
- data/app/assets/javascripts/mbeditor/components/EditorPanel.js +363 -0
- data/app/assets/javascripts/mbeditor/components/FileHistoryPanel.js +112 -0
- data/app/assets/javascripts/mbeditor/components/FileTree.js +304 -0
- data/app/assets/javascripts/mbeditor/components/GitPanel.js +416 -0
- data/app/assets/javascripts/mbeditor/components/MbeditorApp.js +2335 -0
- data/app/assets/javascripts/mbeditor/components/QuickOpenDialog.js +118 -0
- data/app/assets/javascripts/mbeditor/components/ShortcutHelp.js +186 -0
- data/app/assets/javascripts/mbeditor/components/TabBar.js +123 -0
- data/app/assets/javascripts/mbeditor/editor_plugins.js +282 -0
- data/app/assets/javascripts/mbeditor/editor_store.js +53 -0
- data/app/assets/javascripts/mbeditor/file_service.js +77 -0
- data/app/assets/javascripts/mbeditor/git_service.js +104 -0
- data/app/assets/javascripts/mbeditor/search_service.js +53 -0
- data/app/assets/javascripts/mbeditor/tab_manager.js +461 -0
- data/app/assets/stylesheets/mbeditor/application.css +705 -0
- data/app/assets/stylesheets/mbeditor/editor.css +1264 -0
- data/app/controllers/mbeditor/application_controller.rb +10 -0
- data/app/controllers/mbeditor/editors_controller.rb +695 -0
- data/app/controllers/mbeditor/git_controller.rb +188 -0
- data/app/services/mbeditor/git_blame_service.rb +98 -0
- data/app/services/mbeditor/git_commit_graph_service.rb +60 -0
- data/app/services/mbeditor/git_diff_service.rb +71 -0
- data/app/services/mbeditor/git_file_history_service.rb +42 -0
- data/app/services/mbeditor/git_service.rb +82 -0
- data/app/services/mbeditor/redmine_service.rb +86 -0
- data/app/views/layouts/mbeditor/application.html.erb +71 -0
- data/app/views/mbeditor/editors/index.html.erb +1 -0
- data/config/environments/development.rb +53 -0
- data/config/initializers/assets.rb +9 -0
- data/config/routes.rb +37 -0
- data/lib/mbeditor/configuration.rb +16 -0
- data/lib/mbeditor/engine.rb +28 -0
- data/lib/mbeditor/version.rb +3 -0
- data/lib/mbeditor.rb +19 -0
- data/mbeditor.gemspec +30 -0
- data/public/min-maps/vs/base/worker/workerMain.js.map +1 -0
- data/public/monaco-editor/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
- data/public/monaco-editor/vs/base/worker/workerMain.js +31 -0
- data/public/monaco-editor/vs/basic-languages/cameligo/cameligo.js +10 -0
- data/public/monaco-editor/vs/basic-languages/css/css.js +12 -0
- data/public/monaco-editor/vs/basic-languages/dart/dart.js +10 -0
- data/public/monaco-editor/vs/basic-languages/flow9/flow9.js +10 -0
- data/public/monaco-editor/vs/basic-languages/go/go.js +10 -0
- data/public/monaco-editor/vs/basic-languages/handlebars/handlebars.js +440 -0
- data/public/monaco-editor/vs/basic-languages/javascript/javascript.js +10 -0
- data/public/monaco-editor/vs/basic-languages/markdown/markdown.js +10 -0
- data/public/monaco-editor/vs/basic-languages/msdax/msdax.js +10 -0
- data/public/monaco-editor/vs/basic-languages/postiats/postiats.js +10 -0
- data/public/monaco-editor/vs/basic-languages/pug/pug.js +412 -0
- data/public/monaco-editor/vs/basic-languages/restructuredtext/restructuredtext.js +10 -0
- data/public/monaco-editor/vs/basic-languages/ruby/ruby.js +10 -0
- data/public/monaco-editor/vs/basic-languages/sb/sb.js +10 -0
- data/public/monaco-editor/vs/basic-languages/typespec/typespec.js +10 -0
- data/public/monaco-editor/vs/basic-languages/yaml/yaml.js +10 -0
- data/public/monaco-editor/vs/editor/editor.main.css +8 -0
- data/public/monaco-editor/vs/editor/editor.main.js +797 -0
- data/public/monaco-editor/vs/language/typescript/tsMode.js +20 -0
- data/public/monaco-editor/vs/language/typescript/tsWorker.js +51328 -0
- data/public/monaco-editor/vs/loader.js +10 -0
- data/public/monaco-editor/vs/nls.messages.de.js +20 -0
- data/public/monaco-editor/vs/nls.messages.es.js +20 -0
- data/public/monaco-editor/vs/nls.messages.fr.js +18 -0
- data/public/monaco-editor/vs/nls.messages.it.js +18 -0
- data/public/monaco-editor/vs/nls.messages.ja.js +20 -0
- data/public/monaco-editor/vs/nls.messages.ko.js +18 -0
- data/public/monaco-editor/vs/nls.messages.ru.js +20 -0
- data/public/monaco-editor/vs/nls.messages.zh-cn.js +20 -0
- data/public/monaco-editor/vs/nls.messages.zh-tw.js +18 -0
- data/public/monaco_worker.js +5 -0
- data/vendor/assets/javascripts/axios.min.js +2 -0
- data/vendor/assets/javascripts/lodash.min.js +140 -0
- data/vendor/assets/javascripts/marked.min.js +6 -0
- data/vendor/assets/javascripts/minisearch.min.js +2044 -0
- data/vendor/assets/javascripts/prettier-plugin-babel.js +16 -0
- data/vendor/assets/javascripts/prettier-plugin-estree.js +35 -0
- data/vendor/assets/javascripts/prettier-plugin-html.js +19 -0
- data/vendor/assets/javascripts/prettier-plugin-markdown.js +59 -0
- data/vendor/assets/javascripts/prettier-plugin-postcss.js +52 -0
- data/vendor/assets/javascripts/prettier-standalone.js +37 -0
- data/vendor/assets/javascripts/react-dom.min.js +267 -0
- data/vendor/assets/javascripts/react.min.js +31 -0
- data/vendor/assets/stylesheets/fontawesome.min.css +9 -0
- data/vendor/assets/webfonts/fa-brands-400.woff2 +0 -0
- data/vendor/assets/webfonts/fa-regular-400.woff2 +0 -0
- data/vendor/assets/webfonts/fa-solid-900.woff2 +0 -0
- metadata +173 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
'use strict';
|
|
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
|
+
|
|
5
|
+
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; return arr2; } else { return Array.from(arr); } }
|
|
6
|
+
|
|
7
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
8
|
+
|
|
9
|
+
var _React = React;
|
|
10
|
+
var useState = _React.useState;
|
|
11
|
+
var useRef = _React.useRef;
|
|
12
|
+
var useEffect = _React.useEffect;
|
|
13
|
+
var useMemo = _React.useMemo;
|
|
14
|
+
|
|
15
|
+
var FileTree = function FileTree(_ref) {
|
|
16
|
+
var items = _ref.items;
|
|
17
|
+
var onSelect = _ref.onSelect;
|
|
18
|
+
var activePath = _ref.activePath;
|
|
19
|
+
var selectedPath = _ref.selectedPath;
|
|
20
|
+
var onNodeSelect = _ref.onNodeSelect;
|
|
21
|
+
var gitFiles = _ref.gitFiles;
|
|
22
|
+
var expandedDirs = _ref.expandedDirs;
|
|
23
|
+
var onExpandedDirsChange = _ref.onExpandedDirsChange;
|
|
24
|
+
var onFileDoubleClick = _ref.onFileDoubleClick;
|
|
25
|
+
var onContextMenu = _ref.onContextMenu;
|
|
26
|
+
var pendingCreate = _ref.pendingCreate;
|
|
27
|
+
var onCreateConfirm = _ref.onCreateConfirm;
|
|
28
|
+
var onCreateCancel = _ref.onCreateCancel;
|
|
29
|
+
var pendingRename = _ref.pendingRename;
|
|
30
|
+
var onRenameConfirm = _ref.onRenameConfirm;
|
|
31
|
+
var onRenameCancel = _ref.onRenameCancel;
|
|
32
|
+
|
|
33
|
+
var _useState = useState('');
|
|
34
|
+
|
|
35
|
+
var _useState2 = _slicedToArray(_useState, 2);
|
|
36
|
+
|
|
37
|
+
var inlineValue = _useState2[0];
|
|
38
|
+
var setInlineValue = _useState2[1];
|
|
39
|
+
|
|
40
|
+
var inlineRef = useRef(null);
|
|
41
|
+
var committedRef = useRef(false);
|
|
42
|
+
|
|
43
|
+
var renameSelectionEnd = function renameSelectionEnd(name) {
|
|
44
|
+
var value = String(name || '');
|
|
45
|
+
var dotIndex = value.indexOf('.');
|
|
46
|
+
return dotIndex > 0 ? dotIndex : value.length;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Auto-focus the inline input whenever pendingCreate is set
|
|
50
|
+
useEffect(function () {
|
|
51
|
+
if (pendingRename) {
|
|
52
|
+
setInlineValue(pendingRename.currentName || '');
|
|
53
|
+
committedRef.current = false;
|
|
54
|
+
setTimeout(function () {
|
|
55
|
+
if (!inlineRef.current) return;
|
|
56
|
+
var input = inlineRef.current;
|
|
57
|
+
input.focus();
|
|
58
|
+
var end = renameSelectionEnd(pendingRename.currentName);
|
|
59
|
+
input.setSelectionRange(0, end);
|
|
60
|
+
}, 0);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (pendingCreate) {
|
|
65
|
+
setInlineValue('');
|
|
66
|
+
committedRef.current = false;
|
|
67
|
+
setTimeout(function () {
|
|
68
|
+
if (inlineRef.current) inlineRef.current.focus();
|
|
69
|
+
}, 0);
|
|
70
|
+
}
|
|
71
|
+
}, [pendingCreate, pendingRename]);
|
|
72
|
+
|
|
73
|
+
var toggleFolder = function toggleFolder(path, e) {
|
|
74
|
+
e.stopPropagation();
|
|
75
|
+
var next = !(expandedDirs && expandedDirs[path]);
|
|
76
|
+
if (onExpandedDirsChange) onExpandedDirsChange(Object.assign({}, expandedDirs || {}, _defineProperty({}, path, next)));
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
var selectNode = function selectNode(node) {
|
|
80
|
+
if (!node || !onNodeSelect) return;
|
|
81
|
+
onNodeSelect({ path: node.path, name: node.name, type: node.type });
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Build an O(1) lookup map from gitFiles so large trees don't do O(n) scans per row
|
|
85
|
+
var gitStatusMap = useMemo(function () {
|
|
86
|
+
var map = new Map();
|
|
87
|
+
(gitFiles || []).forEach(function (f) { map.set(f.path, f.status); });
|
|
88
|
+
return map;
|
|
89
|
+
}, [gitFiles]);
|
|
90
|
+
|
|
91
|
+
var getGitStatus = function getGitStatus(path) {
|
|
92
|
+
return gitStatusMap.get(path) || null;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
var getTreeStatusMeta = function getTreeStatusMeta(status) {
|
|
96
|
+
var raw = (status || '').trim();
|
|
97
|
+
if (!raw) return null;
|
|
98
|
+
if (raw === '??') return { badge: 'N', cssKey: 'A', title: 'Untracked (new file)' };
|
|
99
|
+
if (raw.startsWith('R')) return { badge: 'R', cssKey: 'R', title: 'Renamed' };
|
|
100
|
+
|
|
101
|
+
var key = raw.charAt(0);
|
|
102
|
+
var titleMap = {
|
|
103
|
+
M: 'Modified',
|
|
104
|
+
A: 'Added',
|
|
105
|
+
D: 'Deleted',
|
|
106
|
+
U: 'Unmerged'
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
return { badge: key || '?', cssKey: key || 'Q', title: titleMap[key] || 'Status' };
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
window.getFileIcon = function (name) {
|
|
113
|
+
var ext = name.split('.').pop().toLowerCase();
|
|
114
|
+
var lName = name.toLowerCase();
|
|
115
|
+
if (lName === 'gemfile' || ext === 'gemspec' || ext === 'lock') return 'fas fa-gem ruby-icon';
|
|
116
|
+
if (ext === 'rb' || ext === 'rake' || lName === 'rakefile') return 'far fa-gem ruby-icon';
|
|
117
|
+
if (ext === 'jsx' || name.endsWith('.js.jsx')) return 'fas fa-atom react-icon';
|
|
118
|
+
if (ext === 'js' || ext === 'mjs' || ext === 'cjs') return 'fa-brands fa-js js-icon';
|
|
119
|
+
if (ext === 'html') return 'fa-brands fa-html5 html-icon';
|
|
120
|
+
if (ext === 'erb') return 'fa-brands fa-html5 erb-icon';
|
|
121
|
+
if (ext === 'css' || ext === 'scss' || ext === 'sass') return 'fa-brands fa-css3-alt css-icon';
|
|
122
|
+
if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'ico', 'webp', 'bmp', 'avif'].includes(ext)) return 'far fa-file-image image-icon';
|
|
123
|
+
if (ext === 'json') return 'fas fa-code json-icon';
|
|
124
|
+
if (ext === 'md' || ext === 'txt') return 'fas fa-file-alt md-icon';
|
|
125
|
+
if (ext === 'yml' || ext === 'yaml') return 'fas fa-cogs yml-icon';
|
|
126
|
+
return 'far fa-file-code';
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
var handleInlineKeyDown = function handleInlineKeyDown(e) {
|
|
130
|
+
var isRename = !!pendingRename;
|
|
131
|
+
if (e.key === 'Enter') {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
e.stopPropagation();
|
|
134
|
+
committedRef.current = true;
|
|
135
|
+
var rawValue = e && e.currentTarget ? e.currentTarget.value : inlineValue;
|
|
136
|
+
var val = String(rawValue || '').trim();
|
|
137
|
+
if (val) {
|
|
138
|
+
if (isRename && onRenameConfirm) onRenameConfirm(val, pendingRename);
|
|
139
|
+
if (!isRename && onCreateConfirm) onCreateConfirm(val);
|
|
140
|
+
} else {
|
|
141
|
+
if (isRename && onRenameCancel) onRenameCancel();
|
|
142
|
+
if (!isRename && onCreateCancel) onCreateCancel();
|
|
143
|
+
}
|
|
144
|
+
} else if (e.key === 'Escape') {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
e.stopPropagation();
|
|
147
|
+
committedRef.current = true;
|
|
148
|
+
if (isRename && onRenameCancel) onRenameCancel();
|
|
149
|
+
if (!isRename && onCreateCancel) onCreateCancel();
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
var handleInlineBlur = function handleInlineBlur() {
|
|
154
|
+
var isRename = !!pendingRename;
|
|
155
|
+
setTimeout(function () {
|
|
156
|
+
if (!committedRef.current) {
|
|
157
|
+
if (isRename && onRenameCancel) onRenameCancel();
|
|
158
|
+
if (!isRename && onCreateCancel) onCreateCancel();
|
|
159
|
+
}
|
|
160
|
+
committedRef.current = false;
|
|
161
|
+
}, 150);
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
var renderInlineRow = function renderInlineRow() {
|
|
165
|
+
var isFolder = pendingCreate.type === 'folder';
|
|
166
|
+
var iconClass = isFolder ? 'fas fa-folder tree-folder-icon' : window.getFileIcon(inlineValue || '') + ' tree-file-icon';
|
|
167
|
+
return React.createElement(
|
|
168
|
+
'div',
|
|
169
|
+
{ key: '__inline-create__', className: 'tree-item tree-item-inline-create' },
|
|
170
|
+
React.createElement(
|
|
171
|
+
'div',
|
|
172
|
+
{ className: 'tree-item-icon' },
|
|
173
|
+
React.createElement('i', { className: iconClass })
|
|
174
|
+
),
|
|
175
|
+
React.createElement('input', {
|
|
176
|
+
ref: inlineRef,
|
|
177
|
+
className: 'tree-inline-input',
|
|
178
|
+
type: 'text',
|
|
179
|
+
value: inlineValue,
|
|
180
|
+
onChange: function (e) {
|
|
181
|
+
return setInlineValue(e.target.value);
|
|
182
|
+
},
|
|
183
|
+
onKeyDown: handleInlineKeyDown,
|
|
184
|
+
onBlur: handleInlineBlur,
|
|
185
|
+
autoComplete: 'off',
|
|
186
|
+
spellCheck: false,
|
|
187
|
+
placeholder: isFolder ? 'folder name' : 'file name'
|
|
188
|
+
})
|
|
189
|
+
);
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
var renderInlineRenameRow = function renderInlineRenameRow(node) {
|
|
193
|
+
var isFolder = node.type === 'folder';
|
|
194
|
+
var iconClass = isFolder ? 'fas fa-folder tree-folder-icon' : window.getFileIcon(inlineValue || node.name || '') + ' tree-file-icon';
|
|
195
|
+
return React.createElement(
|
|
196
|
+
'div',
|
|
197
|
+
{ className: 'tree-item tree-item-inline-create' },
|
|
198
|
+
React.createElement(
|
|
199
|
+
'div',
|
|
200
|
+
{ className: 'tree-item-icon' },
|
|
201
|
+
React.createElement('i', { className: iconClass })
|
|
202
|
+
),
|
|
203
|
+
React.createElement('input', {
|
|
204
|
+
ref: inlineRef,
|
|
205
|
+
className: 'tree-inline-input',
|
|
206
|
+
type: 'text',
|
|
207
|
+
value: inlineValue,
|
|
208
|
+
onChange: function (e) {
|
|
209
|
+
return setInlineValue(e.target.value);
|
|
210
|
+
},
|
|
211
|
+
onKeyDown: handleInlineKeyDown,
|
|
212
|
+
onBlur: handleInlineBlur,
|
|
213
|
+
autoComplete: 'off',
|
|
214
|
+
spellCheck: false,
|
|
215
|
+
placeholder: 'name'
|
|
216
|
+
})
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
var renderTree = function renderTree(nodes, folderPath) {
|
|
221
|
+
var sortedNodes = [].concat(_toConsumableArray(nodes)).sort(function (a, b) {
|
|
222
|
+
if (a.type !== b.type) return a.type === "folder" ? -1 : 1;
|
|
223
|
+
return a.name.localeCompare(b.name);
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
var rows = sortedNodes.map(function (node) {
|
|
227
|
+
var isFolder = node.type === "folder";
|
|
228
|
+
var isExpanded = !!(expandedDirs && expandedDirs[node.path]);
|
|
229
|
+
var isRenamingThisNode = !!(pendingRename && pendingRename.path === node.path);
|
|
230
|
+
var isOpenFile = activePath === node.path;
|
|
231
|
+
var isSelected = selectedPath === node.path;
|
|
232
|
+
var status = getGitStatus(node.path);
|
|
233
|
+
var statusMeta = getTreeStatusMeta(status);
|
|
234
|
+
var isModified = statusMeta && (statusMeta.cssKey === "M" || statusMeta.cssKey === "A");
|
|
235
|
+
|
|
236
|
+
return React.createElement(
|
|
237
|
+
'div',
|
|
238
|
+
{ key: node.path, className: 'file-tree' },
|
|
239
|
+
isRenamingThisNode ? renderInlineRenameRow(node) : React.createElement(
|
|
240
|
+
'div',
|
|
241
|
+
{
|
|
242
|
+
className: 'tree-item ' + (isOpenFile ? "active" : "") + ' ' + (isSelected ? "selected" : "") + ' ' + (isModified ? "modified" : ""),
|
|
243
|
+
onClick: function (e) {
|
|
244
|
+
selectNode(node);
|
|
245
|
+
if (isFolder) {
|
|
246
|
+
toggleFolder(node.path, e);
|
|
247
|
+
} else {
|
|
248
|
+
onSelect(node.path, node.name);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
onDoubleClick: function (e) {
|
|
252
|
+
if (!isFolder && onFileDoubleClick) {
|
|
253
|
+
e.stopPropagation();
|
|
254
|
+
onFileDoubleClick(node.path, node.name);
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
onContextMenu: function (e) {
|
|
258
|
+
e.preventDefault();
|
|
259
|
+
e.stopPropagation();
|
|
260
|
+
selectNode(node);
|
|
261
|
+
if (onContextMenu) onContextMenu(e, node);
|
|
262
|
+
}
|
|
263
|
+
},
|
|
264
|
+
React.createElement(
|
|
265
|
+
'div',
|
|
266
|
+
{ className: 'tree-item-icon' },
|
|
267
|
+
isFolder ? React.createElement('i', { className: 'fas fa-folder' + (isExpanded ? "-open" : "") + ' tree-folder-icon' }) : React.createElement('i', { className: window.getFileIcon(node.name) + ' tree-file-icon' })
|
|
268
|
+
),
|
|
269
|
+
React.createElement(
|
|
270
|
+
'div',
|
|
271
|
+
{ className: 'tree-item-name', title: node.path },
|
|
272
|
+
node.name
|
|
273
|
+
),
|
|
274
|
+
statusMeta && React.createElement(
|
|
275
|
+
'div',
|
|
276
|
+
{ className: 'git-status-badge git-' + statusMeta.cssKey, title: statusMeta.title },
|
|
277
|
+
statusMeta.badge
|
|
278
|
+
)
|
|
279
|
+
),
|
|
280
|
+
isFolder && isExpanded && node.children && React.createElement(
|
|
281
|
+
'div',
|
|
282
|
+
{ style: { paddingLeft: "12px" } },
|
|
283
|
+
renderTree(node.children, node.path)
|
|
284
|
+
)
|
|
285
|
+
);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Inject inline create row at the end of this directory's list
|
|
289
|
+
if (pendingCreate && pendingCreate.parentPath === folderPath) {
|
|
290
|
+
rows.push(renderInlineRow());
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return rows;
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
return React.createElement(
|
|
297
|
+
'div',
|
|
298
|
+
{ className: 'file-tree-root' },
|
|
299
|
+
renderTree(items, '')
|
|
300
|
+
);
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// Expose globally for sprockets require
|
|
304
|
+
window.FileTree = FileTree;
|