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,416 @@
|
|
|
1
|
+
var GitPanel = function GitPanel(_ref) {
|
|
2
|
+
var gitInfo = _ref.gitInfo;
|
|
3
|
+
var error = _ref.error;
|
|
4
|
+
var onOpenFile = _ref.onOpenFile;
|
|
5
|
+
var onOpenDiff = _ref.onOpenDiff;
|
|
6
|
+
var onOpenAllChanges = _ref.onOpenAllChanges;
|
|
7
|
+
var onRefresh = _ref.onRefresh;
|
|
8
|
+
var onClose = _ref.onClose;
|
|
9
|
+
|
|
10
|
+
var useState = React.useState;
|
|
11
|
+
|
|
12
|
+
var _s1 = useState(true); var localExpanded = _s1[0]; var setLocalExpanded = _s1[1];
|
|
13
|
+
var _s2 = useState(true); var branchExpanded = _s2[0]; var setBranchExpanded = _s2[1];
|
|
14
|
+
var _s3 = useState(true); var historyExpanded= _s3[0]; var setHistoryExpanded= _s3[1];
|
|
15
|
+
// { [hash]: true|false }
|
|
16
|
+
var _s4 = useState({}); var expandedCommits = _s4[0]; var setExpandedCommits = _s4[1];
|
|
17
|
+
// { [hash]: { loading, files: [{status,path}], error } }
|
|
18
|
+
var _s5 = useState({}); var commitFiles = _s5[0]; var setCommitFiles = _s5[1];
|
|
19
|
+
|
|
20
|
+
var workingTree = gitInfo && gitInfo.workingTree || [];
|
|
21
|
+
var unpushedFiles = gitInfo && gitInfo.unpushedFiles || [];
|
|
22
|
+
var unpushedCommits = gitInfo && gitInfo.unpushedCommits || [];
|
|
23
|
+
var upstreamBranch = gitInfo && gitInfo.upstreamBranch;
|
|
24
|
+
|
|
25
|
+
// Build a set of unpushed (local) commit hashes for quick lookup
|
|
26
|
+
var localHashes = {};
|
|
27
|
+
unpushedCommits.forEach(function (c) { if (c && c.hash) localHashes[c.hash] = true; });
|
|
28
|
+
|
|
29
|
+
var rawBranchCommits = gitInfo && gitInfo.branchCommits || [];
|
|
30
|
+
var branchCommits = rawBranchCommits.map(function (c) {
|
|
31
|
+
return Object.assign({}, c, { isLocal: !!localHashes[c.hash] });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
var statusMeta = function statusMeta(rawStatus) {
|
|
35
|
+
var raw = (rawStatus || '').trim();
|
|
36
|
+
if (raw === '??') return { badge: 'NEW', cssKey: 'A', description: 'Untracked' };
|
|
37
|
+
if (raw.startsWith('R')) return { badge: 'R', cssKey: 'R', description: 'Renamed' };
|
|
38
|
+
switch (raw.charAt(0)) {
|
|
39
|
+
case 'M': return { badge: 'M', cssKey: 'M', description: 'Modified' };
|
|
40
|
+
case 'A': return { badge: 'A', cssKey: 'A', description: 'Added' };
|
|
41
|
+
case 'D': return { badge: 'D', cssKey: 'D', description: 'Deleted' };
|
|
42
|
+
case 'U': return { badge: 'U', cssKey: 'Q', description: 'Conflict' };
|
|
43
|
+
case 'C': return { badge: 'C', cssKey: 'R', description: 'Copied' };
|
|
44
|
+
default: return { badge: raw || '?', cssKey: 'Q', description: 'Unknown' };
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
var fileIcon = function fileIcon(filename) {
|
|
49
|
+
var ext = (filename || '').split('.').pop().toLowerCase();
|
|
50
|
+
var iconMap = {
|
|
51
|
+
'rb': { cls: 'fas fa-gem', color: '#cc342d' },
|
|
52
|
+
'gemspec': { cls: 'fas fa-gem', color: '#cc342d' },
|
|
53
|
+
'js': { cls: 'fab fa-js', color: '#f0db4f' },
|
|
54
|
+
'ts': { cls: 'fas fa-code', color: '#3178c6' },
|
|
55
|
+
'jsx': { cls: 'fab fa-js', color: '#61dafb' },
|
|
56
|
+
'tsx': { cls: 'fas fa-code', color: '#61dafb' },
|
|
57
|
+
'html': { cls: 'fab fa-html5', color: '#e34f26' },
|
|
58
|
+
'htm': { cls: 'fab fa-html5', color: '#e34f26' },
|
|
59
|
+
'erb': { cls: 'fab fa-html5', color: '#cc342d' },
|
|
60
|
+
'css': { cls: 'fab fa-css3-alt', color: '#1572b6' },
|
|
61
|
+
'scss': { cls: 'fab fa-sass', color: '#cc6699' },
|
|
62
|
+
'sass': { cls: 'fab fa-sass', color: '#cc6699' },
|
|
63
|
+
'md': { cls: 'fab fa-markdown', color: '#7f8b97' },
|
|
64
|
+
'json': { cls: 'fas fa-code', color: '#ffe082' },
|
|
65
|
+
'yml': { cls: 'fas fa-cog', color: '#888' },
|
|
66
|
+
'yaml': { cls: 'fas fa-cog', color: '#888' },
|
|
67
|
+
'png': { cls: 'fas fa-image', color: '#aaa' },
|
|
68
|
+
'jpg': { cls: 'fas fa-image', color: '#aaa' },
|
|
69
|
+
'jpeg': { cls: 'fas fa-image', color: '#aaa' },
|
|
70
|
+
'gif': { cls: 'fas fa-image', color: '#aaa' },
|
|
71
|
+
'svg': { cls: 'fas fa-image', color: '#aaa' },
|
|
72
|
+
'txt': { cls: 'fas fa-file-alt', color: '#888' },
|
|
73
|
+
'sh': { cls: 'fas fa-terminal', color: '#89d185' },
|
|
74
|
+
'lock': { cls: 'fas fa-lock', color: '#888' },
|
|
75
|
+
'pdf': { cls: 'fas fa-file-pdf', color: '#f48771' },
|
|
76
|
+
};
|
|
77
|
+
var icon = iconMap[ext] || { cls: 'fas fa-file-code', color: '#7f8b97' };
|
|
78
|
+
return React.createElement('i', { className: icon.cls + ' git-file-type-icon', style: { color: icon.color } });
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Renders a file row used in Local Changes and Changes in Branch sections
|
|
82
|
+
var renderFileRow = function renderFileRow(item, baseSha, headSha, showOpen) {
|
|
83
|
+
var parts = (item.path || '').split('/');
|
|
84
|
+
var name = parts.pop() || item.path;
|
|
85
|
+
var dir = parts.join('/');
|
|
86
|
+
var meta = statusMeta(item.status);
|
|
87
|
+
var statusClass = 'git-' + meta.cssKey;
|
|
88
|
+
return React.createElement(
|
|
89
|
+
'div',
|
|
90
|
+
{ key: item.path, className: 'git-file-item', style: { cursor: 'pointer' }, onClick: function () { onOpenFile && onOpenFile(item.path, name); } },
|
|
91
|
+
fileIcon(name),
|
|
92
|
+
React.createElement(
|
|
93
|
+
'div',
|
|
94
|
+
{ className: 'git-file-info', title: item.path },
|
|
95
|
+
React.createElement('span', { className: 'git-file-name' }, name),
|
|
96
|
+
dir ? React.createElement('span', { className: 'git-file-dir' }, dir) : null
|
|
97
|
+
),
|
|
98
|
+
(item.added !== undefined || item.removed !== undefined) ? React.createElement(
|
|
99
|
+
'span',
|
|
100
|
+
{ className: 'git-diff-counts' },
|
|
101
|
+
item.added !== undefined ? React.createElement('span', { className: 'git-stat-add' }, '+' + item.added) : null,
|
|
102
|
+
item.removed !== undefined ? React.createElement('span', { className: 'git-stat-del' }, '-' + item.removed) : null
|
|
103
|
+
) : null,
|
|
104
|
+
React.createElement('span', { className: 'git-status-badge ' + statusClass, title: meta.description }, meta.badge),
|
|
105
|
+
React.createElement(
|
|
106
|
+
'div',
|
|
107
|
+
{ className: 'git-file-actions' },
|
|
108
|
+
showOpen ? React.createElement(
|
|
109
|
+
'button',
|
|
110
|
+
{ className: 'git-action-btn', title: 'Open file', onClick: function (e) { e.stopPropagation(); onOpenFile && onOpenFile(item.path, name); } },
|
|
111
|
+
React.createElement('i', { className: 'fas fa-file-code' })
|
|
112
|
+
) : null,
|
|
113
|
+
React.createElement(
|
|
114
|
+
'button',
|
|
115
|
+
{ className: 'git-action-btn', title: 'View diff', onClick: function (e) { e.stopPropagation(); onOpenDiff && onOpenDiff(item.path, name, baseSha, headSha); } },
|
|
116
|
+
React.createElement('i', { className: 'fas fa-exchange-alt' })
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
var toggleCommit = function toggleCommit(hash) {
|
|
123
|
+
var nowExpanded = !expandedCommits[hash];
|
|
124
|
+
setExpandedCommits(function (prev) {
|
|
125
|
+
var next = Object.assign({}, prev);
|
|
126
|
+
next[hash] = nowExpanded;
|
|
127
|
+
return next;
|
|
128
|
+
});
|
|
129
|
+
if (nowExpanded && !commitFiles[hash]) {
|
|
130
|
+
setCommitFiles(function (prev) {
|
|
131
|
+
var next = Object.assign({}, prev);
|
|
132
|
+
next[hash] = { loading: true, files: [], error: null };
|
|
133
|
+
return next;
|
|
134
|
+
});
|
|
135
|
+
GitService.fetchCommitDetail(hash).then(function (data) {
|
|
136
|
+
setCommitFiles(function (prev) {
|
|
137
|
+
var next = Object.assign({}, prev);
|
|
138
|
+
next[hash] = { loading: false, files: data.files || [], error: null };
|
|
139
|
+
return next;
|
|
140
|
+
});
|
|
141
|
+
}).catch(function (err) {
|
|
142
|
+
setCommitFiles(function (prev) {
|
|
143
|
+
var next = Object.assign({}, prev);
|
|
144
|
+
next[hash] = { loading: false, files: [], error: err.message || 'Failed to load files' };
|
|
145
|
+
return next;
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
var renderCommit = function renderCommit(commit, idx) {
|
|
152
|
+
var isFirst = idx === 0;
|
|
153
|
+
var isLast = idx === branchCommits.length - 1;
|
|
154
|
+
var isExpanded = !!expandedCommits[commit.hash];
|
|
155
|
+
var fd = commitFiles[commit.hash];
|
|
156
|
+
var isLocal = commit.isLocal;
|
|
157
|
+
var colorClass = isLocal ? 'commit-local' : 'commit-pushed';
|
|
158
|
+
var dateObj = new Date(commit.date);
|
|
159
|
+
var dateStr = !isNaN(dateObj) ? dateObj.toLocaleString() : (commit.date || '');
|
|
160
|
+
|
|
161
|
+
// Main commit header row
|
|
162
|
+
var headerRow = React.createElement(
|
|
163
|
+
'div',
|
|
164
|
+
{ className: 'commit-row ' + colorClass + (isExpanded ? ' commit-expanded' : ''), onClick: function () { toggleCommit(commit.hash); } },
|
|
165
|
+
React.createElement(
|
|
166
|
+
'div',
|
|
167
|
+
{ className: 'commit-graph-col' },
|
|
168
|
+
!isFirst && React.createElement('div', { className: 'commit-line-top' }),
|
|
169
|
+
React.createElement('div', { className: 'commit-dot ' + (isLocal ? 'dot-local' : 'dot-pushed') }),
|
|
170
|
+
// Draw bottom line if: not the last commit, OR this commit is expanded (sub-items appear in same wrapper)
|
|
171
|
+
(!isLast || isExpanded) && React.createElement('div', { className: 'commit-line-bottom' })
|
|
172
|
+
),
|
|
173
|
+
React.createElement(
|
|
174
|
+
'div',
|
|
175
|
+
{ className: 'commit-info-col' },
|
|
176
|
+
React.createElement(
|
|
177
|
+
'div',
|
|
178
|
+
{ className: 'commit-title', title: commit.title || ('no message \u2014 ' + commit.hash.slice(0, 7)) },
|
|
179
|
+
commit.title
|
|
180
|
+
? commit.title
|
|
181
|
+
: React.createElement('span', { className: 'commit-title-empty' }, commit.hash.slice(0, 7) + ' \u2014 no message')
|
|
182
|
+
),
|
|
183
|
+
React.createElement(
|
|
184
|
+
'div',
|
|
185
|
+
{ className: 'commit-meta' },
|
|
186
|
+
React.createElement('span', { className: 'commit-hash' }, commit.hash.slice(0, 7)),
|
|
187
|
+
' \xB7 ',
|
|
188
|
+
React.createElement('span', { className: 'commit-meta-author' }, commit.author),
|
|
189
|
+
' \xB7 ',
|
|
190
|
+
dateStr
|
|
191
|
+
)
|
|
192
|
+
)
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
// Expanded: nested file rows with continued graph line on the left.
|
|
196
|
+
// These are siblings of headerRow inside a wrapper flex-column, so bottom:0 on
|
|
197
|
+
// the header's spine and top:0 on the sub-row's spine connect without any pixel tricks.
|
|
198
|
+
var subItems = [];
|
|
199
|
+
if (isExpanded) {
|
|
200
|
+
var makeSubRow = function makeSubRow(key, extra, children) {
|
|
201
|
+
return React.createElement(
|
|
202
|
+
'div',
|
|
203
|
+
Object.assign({ key: key, className: 'commit-subfile-row git-file-item ' + colorClass }, extra),
|
|
204
|
+
React.createElement('div', { className: 'commit-graph-col' },
|
|
205
|
+
React.createElement('div', { className: 'commit-line-full' })
|
|
206
|
+
),
|
|
207
|
+
children
|
|
208
|
+
);
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
if (!fd || fd.loading) {
|
|
212
|
+
subItems.push(makeSubRow(commit.hash + '-load', {},
|
|
213
|
+
React.createElement('span', { className: 'git-commit-loading' }, 'Loading\u2026')
|
|
214
|
+
));
|
|
215
|
+
} else if (fd.error) {
|
|
216
|
+
subItems.push(makeSubRow(commit.hash + '-err', {},
|
|
217
|
+
React.createElement('span', { className: 'git-commit-loading' }, fd.error)
|
|
218
|
+
));
|
|
219
|
+
} else if (fd.files.length === 0) {
|
|
220
|
+
subItems.push(makeSubRow(commit.hash + '-empty', {},
|
|
221
|
+
React.createElement('span', { className: 'git-commit-loading' }, 'No files changed.')
|
|
222
|
+
));
|
|
223
|
+
} else {
|
|
224
|
+
fd.files.forEach(function (f, fi) {
|
|
225
|
+
var fParts = (f.path || '').split('/');
|
|
226
|
+
var fName = fParts.pop() || f.path;
|
|
227
|
+
var fDir = fParts.join('/');
|
|
228
|
+
var fStatus = (f.status || '').trim();
|
|
229
|
+
var fCssKey = fStatus === 'M' ? 'M' : fStatus === 'A' ? 'A' : fStatus === 'D' ? 'D' : fStatus.startsWith('R') ? 'R' : 'Q';
|
|
230
|
+
subItems.push(makeSubRow(commit.hash + '-f-' + fi, { style: { cursor: 'pointer' }, onClick: function () { onOpenFile && onOpenFile(f.path, fName); } },
|
|
231
|
+
[
|
|
232
|
+
fileIcon(fName),
|
|
233
|
+
React.createElement(
|
|
234
|
+
'div',
|
|
235
|
+
{ key: 'info', className: 'git-file-info', title: f.path },
|
|
236
|
+
React.createElement('span', { className: 'git-file-name' }, fName),
|
|
237
|
+
fDir ? React.createElement('span', { className: 'git-file-dir' }, fDir) : null
|
|
238
|
+
),
|
|
239
|
+
(f.added !== undefined || f.removed !== undefined) ? React.createElement(
|
|
240
|
+
'span',
|
|
241
|
+
{ key: 'counts', className: 'git-diff-counts' },
|
|
242
|
+
f.added !== undefined ? React.createElement('span', { key: 'a', className: 'git-stat-add' }, '+' + f.added) : null,
|
|
243
|
+
f.removed !== undefined ? React.createElement('span', { key: 'r', className: 'git-stat-del' }, '-' + f.removed) : null
|
|
244
|
+
) : null,
|
|
245
|
+
React.createElement('span', { key: 'badge', className: 'git-status-badge git-' + fCssKey }, fStatus || '?'),
|
|
246
|
+
React.createElement(
|
|
247
|
+
'div',
|
|
248
|
+
{ key: 'actions', className: 'git-file-actions' },
|
|
249
|
+
React.createElement(
|
|
250
|
+
'button',
|
|
251
|
+
{ className: 'git-action-btn', title: 'View diff for this commit', onClick: function (e) { e.stopPropagation(); onOpenDiff && onOpenDiff(f.path, fName, commit.hash + '^', commit.hash); } },
|
|
252
|
+
React.createElement('i', { className: 'fas fa-exchange-alt' })
|
|
253
|
+
)
|
|
254
|
+
)
|
|
255
|
+
]
|
|
256
|
+
));
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Wrap the header row + sub-items in a single flex-column group.
|
|
262
|
+
// A 6px spacer element at the end of every non-last group draws the
|
|
263
|
+
// spine line through the visual gap between groups.
|
|
264
|
+
return React.createElement(
|
|
265
|
+
'div',
|
|
266
|
+
{ key: commit.hash, className: 'commit-group ' + colorClass + (isExpanded ? ' is-expanded' : '') + (isLast ? ' is-last' : '') },
|
|
267
|
+
headerRow,
|
|
268
|
+
subItems,
|
|
269
|
+
!isLast && React.createElement('div', { className: 'commit-spacer ' + colorClass },
|
|
270
|
+
React.createElement('div', { className: 'commit-graph-col' },
|
|
271
|
+
React.createElement('div', { className: 'commit-line-full' })
|
|
272
|
+
)
|
|
273
|
+
)
|
|
274
|
+
);
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// One element per commit (wrapper div)
|
|
278
|
+
var historyRows = branchCommits.map(function (commit, idx) {
|
|
279
|
+
return renderCommit(commit, idx);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
return React.createElement(
|
|
283
|
+
'aside',
|
|
284
|
+
{ className: 'ide-git-panel', 'aria-label': 'Git panel' },
|
|
285
|
+
|
|
286
|
+
// Header
|
|
287
|
+
React.createElement(
|
|
288
|
+
'div',
|
|
289
|
+
{ className: 'ide-git-panel-header' },
|
|
290
|
+
React.createElement(
|
|
291
|
+
'div',
|
|
292
|
+
{ className: 'ide-git-panel-header-info' },
|
|
293
|
+
React.createElement('div', { className: 'ide-git-panel-title' }, 'Source Control'),
|
|
294
|
+
React.createElement(
|
|
295
|
+
'div',
|
|
296
|
+
{ className: 'ide-git-panel-branch' },
|
|
297
|
+
React.createElement('i', { className: 'fas fa-code-branch', style: { marginRight: '5px', fontSize: '11px', opacity: 0.7 } }),
|
|
298
|
+
gitInfo && gitInfo.branch || 'unknown branch',
|
|
299
|
+
gitInfo && gitInfo.ahead > 0 && React.createElement('span', { className: 'git-ahead-chip', title: gitInfo.ahead + ' ahead' }, '\u2191' + gitInfo.ahead),
|
|
300
|
+
gitInfo && gitInfo.behind > 0 && React.createElement('span', { className: 'git-behind-chip', title: gitInfo.behind + ' behind' }, '\u2193' + gitInfo.behind)
|
|
301
|
+
)
|
|
302
|
+
),
|
|
303
|
+
React.createElement(
|
|
304
|
+
'div',
|
|
305
|
+
{ className: 'ide-git-panel-actions' },
|
|
306
|
+
onRefresh && React.createElement(
|
|
307
|
+
'button',
|
|
308
|
+
{ className: 'git-header-btn', onClick: onRefresh, title: 'Refresh' },
|
|
309
|
+
React.createElement('i', { className: 'fas fa-sync-alt' })
|
|
310
|
+
),
|
|
311
|
+
onClose && React.createElement(
|
|
312
|
+
'button',
|
|
313
|
+
{ className: 'git-header-btn', onClick: onClose, title: 'Close panel' },
|
|
314
|
+
React.createElement('i', { className: 'fas fa-times' })
|
|
315
|
+
)
|
|
316
|
+
)
|
|
317
|
+
),
|
|
318
|
+
|
|
319
|
+
error && React.createElement('div', { className: 'git-error' }, error),
|
|
320
|
+
|
|
321
|
+
// ── Section 1: Local Changes ────────────────────────────────────────────
|
|
322
|
+
React.createElement(
|
|
323
|
+
'div',
|
|
324
|
+
{ className: 'git-section ' + (localExpanded ? 'expanded' : '') },
|
|
325
|
+
React.createElement(
|
|
326
|
+
'div',
|
|
327
|
+
{ className: 'git-section-title' },
|
|
328
|
+
React.createElement(
|
|
329
|
+
'div',
|
|
330
|
+
{ className: 'git-section-title-main hoverable', onClick: function () { setLocalExpanded(!localExpanded); } },
|
|
331
|
+
React.createElement('i', { className: 'fas ' + (localExpanded ? 'fa-chevron-down' : 'fa-chevron-right'), style: { width: '14px', fontSize: '10px' } }),
|
|
332
|
+
' Local Changes\u2002',
|
|
333
|
+
React.createElement('span', { className: 'git-section-count' }, workingTree.length)
|
|
334
|
+
),
|
|
335
|
+
workingTree.length > 0 && React.createElement(
|
|
336
|
+
'button',
|
|
337
|
+
{
|
|
338
|
+
className: 'git-section-action-btn',
|
|
339
|
+
title: 'View all local changes',
|
|
340
|
+
onClick: function (e) { e.stopPropagation(); onOpenAllChanges && onOpenAllChanges('local', 'Local Changes'); }
|
|
341
|
+
},
|
|
342
|
+
React.createElement('i', { className: 'fas fa-layer-group' })
|
|
343
|
+
)
|
|
344
|
+
),
|
|
345
|
+
localExpanded && React.createElement(
|
|
346
|
+
'div',
|
|
347
|
+
{ className: 'git-list' },
|
|
348
|
+
workingTree.length === 0
|
|
349
|
+
? React.createElement('div', { className: 'git-empty' }, 'No local changes.')
|
|
350
|
+
: workingTree.map(function (item, idx) { return renderFileRow(item, 'HEAD', null, false); })
|
|
351
|
+
)
|
|
352
|
+
),
|
|
353
|
+
|
|
354
|
+
// ── Section 2: Changes in Branch ───────────────────────────────────────
|
|
355
|
+
React.createElement(
|
|
356
|
+
'div',
|
|
357
|
+
{ className: 'git-section ' + (branchExpanded ? 'expanded' : '') },
|
|
358
|
+
React.createElement(
|
|
359
|
+
'div',
|
|
360
|
+
{ className: 'git-section-title' },
|
|
361
|
+
React.createElement(
|
|
362
|
+
'div',
|
|
363
|
+
{ className: 'git-section-title-main hoverable', onClick: function () { setBranchExpanded(!branchExpanded); } },
|
|
364
|
+
React.createElement('i', { className: 'fas ' + (branchExpanded ? 'fa-chevron-down' : 'fa-chevron-right'), style: { width: '14px', fontSize: '10px' } }),
|
|
365
|
+
' Changes in Branch\u2002',
|
|
366
|
+
React.createElement('span', { className: 'git-section-count' }, unpushedFiles.length)
|
|
367
|
+
),
|
|
368
|
+
unpushedFiles.length > 0 && React.createElement(
|
|
369
|
+
'button',
|
|
370
|
+
{
|
|
371
|
+
className: 'git-section-action-btn',
|
|
372
|
+
title: 'View all branch changes',
|
|
373
|
+
onClick: function (e) { e.stopPropagation(); onOpenAllChanges && onOpenAllChanges('branch', 'Changes in Branch'); }
|
|
374
|
+
},
|
|
375
|
+
React.createElement('i', { className: 'fas fa-layer-group' })
|
|
376
|
+
)
|
|
377
|
+
),
|
|
378
|
+
branchExpanded && React.createElement(
|
|
379
|
+
React.Fragment,
|
|
380
|
+
null,
|
|
381
|
+
upstreamBranch
|
|
382
|
+
? React.createElement('div', { className: 'git-hint' }, 'All files changed vs ', React.createElement('code', null, upstreamBranch))
|
|
383
|
+
: React.createElement('div', { className: 'git-hint' }, 'No upstream branch tracked.'),
|
|
384
|
+
React.createElement(
|
|
385
|
+
'div',
|
|
386
|
+
{ className: 'git-list' },
|
|
387
|
+
unpushedFiles.length === 0
|
|
388
|
+
? React.createElement('div', { className: 'git-empty' }, 'No changes vs upstream.')
|
|
389
|
+
: unpushedFiles.map(function (item) { return renderFileRow(item, upstreamBranch, 'HEAD', true); })
|
|
390
|
+
)
|
|
391
|
+
)
|
|
392
|
+
),
|
|
393
|
+
|
|
394
|
+
// ── Section 3: History ─────────────────────────────────────────────────
|
|
395
|
+
React.createElement(
|
|
396
|
+
'div',
|
|
397
|
+
{ className: 'git-section git-history-section ' + (historyExpanded ? 'expanded' : '') },
|
|
398
|
+
React.createElement(
|
|
399
|
+
'div',
|
|
400
|
+
{ className: 'git-section-title hoverable', onClick: function () { setHistoryExpanded(!historyExpanded); } },
|
|
401
|
+
React.createElement('i', { className: 'fas ' + (historyExpanded ? 'fa-chevron-down' : 'fa-chevron-right'), style: { width: '14px', fontSize: '10px' } }),
|
|
402
|
+
' History\u2002',
|
|
403
|
+
React.createElement('span', { className: 'git-section-count' }, branchCommits.length)
|
|
404
|
+
),
|
|
405
|
+
historyExpanded && React.createElement(
|
|
406
|
+
'div',
|
|
407
|
+
{ className: 'git-history-graph-wrap' },
|
|
408
|
+
branchCommits.length === 0
|
|
409
|
+
? React.createElement('div', { className: 'git-empty' }, 'No commit history.')
|
|
410
|
+
: historyRows
|
|
411
|
+
)
|
|
412
|
+
)
|
|
413
|
+
);
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
window.GitPanel = GitPanel;
|