reslop 0.2.5 → 0.2.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.
- package/CHANGELOG.md +22 -1
- package/LICENSE +1 -1
- package/README.md +11 -11
- package/bin/reslop.js +3 -8
- package/lib/ansi.js +72 -19
- package/lib/api.js +1 -1
- package/lib/capabilities.js +8 -8
- package/lib/cli.js +61 -75
- package/lib/clipboard.js +39 -47
- package/lib/dashboard/git.js +128 -0
- package/lib/dashboard/model.js +357 -0
- package/lib/dashboard/npm.js +290 -0
- package/lib/dashboard/tree.js +278 -0
- package/lib/deps-diff.js +197 -402
- package/lib/deps.js +113 -240
- package/lib/detect.js +8 -18
- package/lib/diff/align.js +41 -113
- package/lib/diff/diff.js +12 -43
- package/lib/diff/display.js +25 -36
- package/lib/diff/edit.js +6 -20
- package/lib/diff/inline.js +76 -144
- package/lib/diff/items.js +33 -47
- package/lib/diff/parse.js +28 -56
- package/lib/diff/patch.js +12 -33
- package/lib/diff/unit.js +79 -178
- package/lib/editor.js +52 -69
- package/lib/files.js +79 -91
- package/lib/find.js +61 -0
- package/lib/git-branches.js +254 -416
- package/lib/git-deps.js +148 -272
- package/lib/git-reword-todo.js +5 -13
- package/lib/git-worktree.js +161 -214
- package/lib/git.js +21 -49
- package/lib/github.js +67 -181
- package/lib/gitlab.js +40 -90
- package/lib/highlight/bash.js +55 -177
- package/lib/highlight/core.js +155 -141
- package/lib/highlight/css.js +25 -58
- package/lib/highlight/csv.js +19 -37
- package/lib/highlight/dart.js +72 -213
- package/lib/highlight/dot.js +14 -14
- package/lib/highlight/html.js +42 -63
- package/lib/highlight/js.js +177 -506
- package/lib/highlight/json.js +17 -37
- package/lib/highlight/log.js +19 -25
- package/lib/highlight/txt.js +7 -10
- package/lib/highlight.js +17 -46
- package/lib/keys.js +75 -83
- package/lib/manifest.js +67 -126
- package/lib/npm-commands.js +120 -169
- package/lib/remote.js +140 -190
- package/lib/render/branches.js +63 -61
- package/lib/render/chrome.js +412 -347
- package/lib/render/commits.js +160 -361
- package/lib/render/dash-activity.js +212 -0
- package/lib/render/dash-blocks.js +496 -0
- package/lib/render/dash-table.js +295 -0
- package/lib/render/dashboard.js +62 -0
- package/lib/render/diff.js +123 -258
- package/lib/render/files.js +60 -86
- package/lib/render/frame.js +82 -117
- package/lib/render/notes.js +150 -210
- package/lib/render/npm.js +213 -177
- package/lib/render/packages.js +93 -0
- package/lib/render/present.js +4 -11
- package/lib/render/primitives.js +77 -172
- package/lib/render/render.js +5 -14
- package/lib/render/report.js +43 -0
- package/lib/render/repos.js +226 -0
- package/lib/render/search.js +25 -0
- package/lib/render/tiles.js +355 -0
- package/lib/render/unit.js +15 -31
- package/lib/report-model.js +110 -33
- package/lib/report-parse.js +56 -37
- package/lib/report-render.js +102 -59
- package/lib/report-run.js +87 -77
- package/lib/report-test.js +221 -99
- package/lib/report-tools.js +96 -154
- package/lib/review-merge.js +33 -41
- package/lib/review.js +69 -129
- package/lib/runs.js +225 -0
- package/lib/select.js +53 -91
- package/lib/session/accessors.js +14 -21
- package/lib/session/actions.js +189 -65
- package/lib/session/branches.js +164 -222
- package/lib/session/change-actions.js +49 -119
- package/lib/session/commit.js +298 -352
- package/lib/session/compose.js +572 -715
- package/lib/session/dashboard.js +530 -0
- package/lib/session/dispatch.js +197 -171
- package/lib/session/files-pane.js +92 -45
- package/lib/session/find.js +94 -0
- package/lib/session/items.js +6 -17
- package/lib/session/lifecycle.js +420 -466
- package/lib/session/load.js +1 -14
- package/lib/session/navigation.js +4 -2
- package/lib/session/npm.js +403 -420
- package/lib/session/ops.js +5 -13
- package/lib/session/packages.js +143 -0
- package/lib/session/pointer.js +30 -14
- package/lib/session/progress.js +39 -30
- package/lib/session/review.js +1 -3
- package/lib/session/tasks.js +277 -236
- package/lib/session/templates.js +51 -59
- package/lib/session/terminal.js +85 -132
- package/lib/session/view.js +59 -80
- package/lib/session/watch.js +201 -212
- package/lib/session/workspace.js +455 -0
- package/lib/session.js +95 -161
- package/lib/update.js +44 -111
- package/lib/utilities.js +46 -88
- package/lib/workspace.js +166 -0
- package/lib/wrap.js +29 -55
- package/package.json +1 -1
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const files = require('../files.js');
|
|
4
|
+
const { fileEntries, fileTotals } = files;
|
|
5
|
+
const review = require('../review.js');
|
|
6
|
+
const { noteCounts } = review;
|
|
7
|
+
const runs = require('../runs.js');
|
|
8
|
+
const { readRuns, settleRecord, isRunsRel } = runs;
|
|
9
|
+
const tree = require('../dashboard/tree.js');
|
|
10
|
+
const { FileIndex, HEAT_MS } = tree;
|
|
11
|
+
const gitInfo = require('../dashboard/git.js');
|
|
12
|
+
const { readGitSummary } = gitInfo;
|
|
13
|
+
const npmInfo = require('../dashboard/npm.js');
|
|
14
|
+
const { readNpmSummary } = npmInfo;
|
|
15
|
+
const model = require('../dashboard/model.js');
|
|
16
|
+
const { buildModel, minuteOf, MINUTE_MS, npmModel } = model;
|
|
17
|
+
const filesPane = require('./files-pane.js');
|
|
18
|
+
const watch = require('./watch.js');
|
|
19
|
+
const { UNKNOWN_PATH, MODULES_STAMP } = watch;
|
|
20
|
+
|
|
21
|
+
const TICK_ID = 'dashboard';
|
|
22
|
+
const HEAT_TIMER = 'dashboard-heat';
|
|
23
|
+
const AGE_TIMER = 'dashboard-age';
|
|
24
|
+
const MINUTE_TIMER = 'dashboard-minute';
|
|
25
|
+
const BLINK_TIMER = 'dashboard-blink';
|
|
26
|
+
const BLINK_MS = 3000;
|
|
27
|
+
const MINUTE_KEEP = 360;
|
|
28
|
+
const SWITCHES = 4;
|
|
29
|
+
const RUN_MARK = { failed: 'fail', passed: 'pass', aborted: 'abort' };
|
|
30
|
+
const GIT_NAMES = new Set([
|
|
31
|
+
'HEAD',
|
|
32
|
+
'packed-refs',
|
|
33
|
+
'FETCH_HEAD',
|
|
34
|
+
'ORIG_HEAD',
|
|
35
|
+
'refs',
|
|
36
|
+
'logs',
|
|
37
|
+
'rebase-merge',
|
|
38
|
+
'rebase-apply',
|
|
39
|
+
]);
|
|
40
|
+
const NPM_FILES = new Set(['package.json', 'package-lock.json', MODULES_STAMP]);
|
|
41
|
+
const AGE_FAST_MS = 1000;
|
|
42
|
+
const AGE_MID_MS = 30000;
|
|
43
|
+
const AGE_SLOW_MS = 600000;
|
|
44
|
+
|
|
45
|
+
class Coalesced {
|
|
46
|
+
constructor(run, onDone) {
|
|
47
|
+
this.run = run;
|
|
48
|
+
this.onDone = onDone;
|
|
49
|
+
this.running = false;
|
|
50
|
+
this.dirty = false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
request() {
|
|
54
|
+
this.dirty = true;
|
|
55
|
+
if (!this.running) void this.pump();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async pump() {
|
|
59
|
+
this.running = true;
|
|
60
|
+
while (this.dirty) {
|
|
61
|
+
this.dirty = false;
|
|
62
|
+
try {
|
|
63
|
+
await this.run();
|
|
64
|
+
} catch {
|
|
65
|
+
// keep the previous data until the next event
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
this.running = false;
|
|
69
|
+
this.onDone();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const totalsKey = (totals) =>
|
|
74
|
+
[
|
|
75
|
+
totals.stagedAdded,
|
|
76
|
+
totals.unstagedAdded,
|
|
77
|
+
totals.stagedRemoved,
|
|
78
|
+
totals.unstagedRemoved,
|
|
79
|
+
totals.remaining,
|
|
80
|
+
].join(':');
|
|
81
|
+
|
|
82
|
+
const classify = (paths) => {
|
|
83
|
+
const found = { files: [], git: false, npm: false, runs: false, all: false };
|
|
84
|
+
for (const rel of paths) {
|
|
85
|
+
if (rel === UNKNOWN_PATH) {
|
|
86
|
+
found.all = true;
|
|
87
|
+
} else if (rel.startsWith('.git/')) {
|
|
88
|
+
if (GIT_NAMES.has(rel.split('/')[1])) found.git = true;
|
|
89
|
+
} else if (isRunsRel(rel)) {
|
|
90
|
+
found.runs = true;
|
|
91
|
+
} else {
|
|
92
|
+
if (NPM_FILES.has(rel)) found.npm = true;
|
|
93
|
+
found.files.push(rel);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return found;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const ageDelay = (ageMs) => {
|
|
100
|
+
if (ageMs < 90000) return AGE_FAST_MS;
|
|
101
|
+
if (ageMs < 5400000) return AGE_MID_MS;
|
|
102
|
+
return AGE_SLOW_MS;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
class Dashboard {
|
|
106
|
+
constructor(ui) {
|
|
107
|
+
this.ui = ui;
|
|
108
|
+
this.epoch = 0;
|
|
109
|
+
const done = () => this.done();
|
|
110
|
+
this.tasks = {
|
|
111
|
+
files: new Coalesced(() => this.runFiles(), done),
|
|
112
|
+
git: new Coalesced(() => this.runGit(), done),
|
|
113
|
+
npm: new Coalesced(() => this.runNpm(), done),
|
|
114
|
+
runs: new Coalesced(() => this.runRuns(), done),
|
|
115
|
+
};
|
|
116
|
+
this.clear();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
clear() {
|
|
120
|
+
this.epoch += 1;
|
|
121
|
+
this.active = false;
|
|
122
|
+
this.index = null;
|
|
123
|
+
this.touch = new Set();
|
|
124
|
+
this.fileDelta = null;
|
|
125
|
+
this.git = null;
|
|
126
|
+
this.npm = null;
|
|
127
|
+
this.runs = [];
|
|
128
|
+
this.totals = null;
|
|
129
|
+
this.totalsKey = '';
|
|
130
|
+
this.diffDelta = null;
|
|
131
|
+
this.minutes = new Map();
|
|
132
|
+
this.activityAt = 0;
|
|
133
|
+
this.rebaseOn = false;
|
|
134
|
+
this.switches = [];
|
|
135
|
+
this.branchAt = new Map();
|
|
136
|
+
this.branchSha = new Map();
|
|
137
|
+
this.lastSha = '';
|
|
138
|
+
this.marks = { npm: 0, commit: 0, branches: 0 };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
root() {
|
|
142
|
+
return this.ui.top || this.ui.cwd;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
visible() {
|
|
146
|
+
return this.ui.uiOpen && this.ui.nav.pane === 'dashboard';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
paintIfVisible() {
|
|
150
|
+
if (this.visible()) this.ui.paint();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
done() {
|
|
154
|
+
this.afterDraw();
|
|
155
|
+
this.paintIfVisible();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
hotUntil() {
|
|
159
|
+
const { marks, index, fileDelta, diffDelta } = this;
|
|
160
|
+
return Math.max(
|
|
161
|
+
index ? index.hotUntil() : 0,
|
|
162
|
+
fileDelta ? fileDelta.at + HEAT_MS : 0,
|
|
163
|
+
diffDelta ? diffDelta.at + HEAT_MS : 0,
|
|
164
|
+
marks.npm + HEAT_MS,
|
|
165
|
+
marks.commit + HEAT_MS,
|
|
166
|
+
marks.branches + HEAT_MS,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
liveRuns() {
|
|
171
|
+
return this.runs.map((run) => settleRecord(run));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
youngest(runs) {
|
|
175
|
+
const last = this.git && this.git.commits.last;
|
|
176
|
+
let at = last ? last.at : 0;
|
|
177
|
+
for (const run of runs) at = Math.max(at, run.endedAt, run.startedAt);
|
|
178
|
+
return at;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
cancelTimers() {
|
|
182
|
+
const { progress, term } = this.ui;
|
|
183
|
+
progress.stop(TICK_ID);
|
|
184
|
+
term.cancel(HEAT_TIMER);
|
|
185
|
+
term.cancel(AGE_TIMER);
|
|
186
|
+
term.cancel(MINUTE_TIMER);
|
|
187
|
+
term.cancel(BLINK_TIMER);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
bucket(at) {
|
|
191
|
+
const minute = minuteOf(at);
|
|
192
|
+
let newest = minute;
|
|
193
|
+
for (const key of this.minutes.keys()) {
|
|
194
|
+
if (key > newest) newest = key;
|
|
195
|
+
}
|
|
196
|
+
if (minute < newest - MINUTE_KEEP) return null;
|
|
197
|
+
let row = this.minutes.get(minute);
|
|
198
|
+
if (!row) {
|
|
199
|
+
row = { level: 0, added: 0, removed: 0, marks: [] };
|
|
200
|
+
this.minutes.set(minute, row);
|
|
201
|
+
}
|
|
202
|
+
const oldest = newest - MINUTE_KEEP;
|
|
203
|
+
for (const key of this.minutes.keys()) {
|
|
204
|
+
if (key < oldest) this.minutes.delete(key);
|
|
205
|
+
}
|
|
206
|
+
return row;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
touchActivity(at) {
|
|
210
|
+
if (at > this.activityAt) this.activityAt = at;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
heat(at, added, removed = 0) {
|
|
214
|
+
const plus = Math.max(0, added || 0);
|
|
215
|
+
const minus = Math.max(0, removed || 0);
|
|
216
|
+
if (!at || plus + minus <= 0) return;
|
|
217
|
+
const row = this.bucket(at);
|
|
218
|
+
if (!row) return;
|
|
219
|
+
row.added += plus;
|
|
220
|
+
row.removed += minus;
|
|
221
|
+
row.level += plus + minus;
|
|
222
|
+
this.touchActivity(at);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
mark(at, kind) {
|
|
226
|
+
if (!at || !kind) return;
|
|
227
|
+
const row = this.bucket(at);
|
|
228
|
+
if (!row || row.marks.includes(kind)) return;
|
|
229
|
+
row.marks.push(kind);
|
|
230
|
+
this.touchActivity(at);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
noteCommits(next) {
|
|
234
|
+
const recent = next.commits.recent;
|
|
235
|
+
for (const entry of recent) this.mark(entry.at, 'commit');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
noteRebase(next, now) {
|
|
239
|
+
const rebasing = Boolean(next.rebase);
|
|
240
|
+
if (rebasing && !this.rebaseOn) this.mark(now, 'rebase');
|
|
241
|
+
this.rebaseOn = rebasing;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
noteRuns(runs) {
|
|
245
|
+
for (const run of runs) {
|
|
246
|
+
const kind = RUN_MARK[run.status];
|
|
247
|
+
if (kind) this.mark(run.endedAt || run.startedAt, kind);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
isRunLive() {
|
|
252
|
+
for (const run of this.liveRuns()) {
|
|
253
|
+
if (run.status === 'running') return true;
|
|
254
|
+
}
|
|
255
|
+
const npm = this.ui.npm.lastRun;
|
|
256
|
+
return Boolean(npm && npm.running);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
isBusy() {
|
|
260
|
+
if (this.git && this.git.rebase) return true;
|
|
261
|
+
return this.isRunLive();
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
liveActivity(now) {
|
|
265
|
+
if (this.isBusy()) return true;
|
|
266
|
+
return now - this.activityAt < BLINK_MS;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
activityView(now) {
|
|
270
|
+
const minutes = [];
|
|
271
|
+
for (const [at, row] of this.minutes) {
|
|
272
|
+
minutes.push({
|
|
273
|
+
at,
|
|
274
|
+
level: row.level,
|
|
275
|
+
added: row.added,
|
|
276
|
+
removed: row.removed,
|
|
277
|
+
marks: row.marks.slice(),
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
return { minutes, live: this.liveActivity(now) };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
afterDraw() {
|
|
284
|
+
if (!this.active) return;
|
|
285
|
+
if (!this.visible()) return void this.cancelTimers();
|
|
286
|
+
const { progress, term } = this.ui;
|
|
287
|
+
const now = Date.now();
|
|
288
|
+
if (this.isBusy()) this.touchActivity(now);
|
|
289
|
+
const until = this.hotUntil();
|
|
290
|
+
const hot = now < until;
|
|
291
|
+
const live = this.liveActivity(now);
|
|
292
|
+
if (live || hot) progress.start(TICK_ID);
|
|
293
|
+
else progress.stop(TICK_ID);
|
|
294
|
+
const repaint = () => this.paintIfVisible();
|
|
295
|
+
if (hot) term.later(HEAT_TIMER, repaint, until - now + 20);
|
|
296
|
+
const at = this.youngest(this.liveRuns());
|
|
297
|
+
const delay = at ? ageDelay(now - at) : AGE_SLOW_MS;
|
|
298
|
+
term.later(AGE_TIMER, repaint, delay);
|
|
299
|
+
const minuteLeft = MINUTE_MS - (now % MINUTE_MS) + 20;
|
|
300
|
+
term.later(MINUTE_TIMER, repaint, minuteLeft);
|
|
301
|
+
const blinkLeft = this.activityAt + BLINK_MS - now;
|
|
302
|
+
if (blinkLeft > 0) term.later(BLINK_TIMER, repaint, blinkLeft + 20);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async runFiles() {
|
|
306
|
+
const { epoch, index } = this;
|
|
307
|
+
if (!index) return;
|
|
308
|
+
const wasReady = index.ready;
|
|
309
|
+
const before = index.summary().total;
|
|
310
|
+
const paths = [...this.touch];
|
|
311
|
+
this.touch.clear();
|
|
312
|
+
const changed = await index.touch(paths);
|
|
313
|
+
if (epoch !== this.epoch || !changed || !wasReady) return;
|
|
314
|
+
const after = index.summary().total;
|
|
315
|
+
const lines = after.lines - before.lines;
|
|
316
|
+
const bytes = after.bytes - before.bytes;
|
|
317
|
+
if (!lines && !bytes) return;
|
|
318
|
+
const at = Date.now();
|
|
319
|
+
this.fileDelta = { lines, at };
|
|
320
|
+
const plus = lines > 0 ? lines : 0;
|
|
321
|
+
const minus = lines < 0 ? -lines : 0;
|
|
322
|
+
this.heat(at, plus || (minus ? 0 : 1), minus);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
noteShas(next, now) {
|
|
326
|
+
const seen = this.branchSha;
|
|
327
|
+
const known = seen.size > 0;
|
|
328
|
+
let changed = false;
|
|
329
|
+
for (const entry of next.branches) {
|
|
330
|
+
if (known && seen.get(entry.name) !== entry.sha) {
|
|
331
|
+
this.branchAt.set(entry.name, now);
|
|
332
|
+
changed = true;
|
|
333
|
+
}
|
|
334
|
+
seen.set(entry.name, entry.sha);
|
|
335
|
+
}
|
|
336
|
+
return changed;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
noteSwitch(next, now) {
|
|
340
|
+
const prev = this.git;
|
|
341
|
+
if (!prev || !prev.branch || !next.branch) return false;
|
|
342
|
+
if (prev.branch === next.branch) return false;
|
|
343
|
+
const entry = { from: prev.branch, to: next.branch, at: now };
|
|
344
|
+
this.switches = [entry, ...this.switches].slice(0, SWITCHES);
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
async runGit() {
|
|
349
|
+
const epoch = this.epoch;
|
|
350
|
+
const next = await readGitSummary(this.root());
|
|
351
|
+
if (epoch !== this.epoch) return;
|
|
352
|
+
const now = Date.now();
|
|
353
|
+
const moved = this.noteShas(next, now);
|
|
354
|
+
const switched = this.noteSwitch(next, now);
|
|
355
|
+
if (moved || switched) this.marks.branches = now;
|
|
356
|
+
if (switched) this.mark(now, 'branch');
|
|
357
|
+
const sha = next.commits.last ? next.commits.last.sha : '';
|
|
358
|
+
if (this.lastSha && sha !== this.lastSha) this.marks.commit = now;
|
|
359
|
+
this.lastSha = sha;
|
|
360
|
+
this.noteCommits(next);
|
|
361
|
+
this.noteRebase(next, now);
|
|
362
|
+
this.git = next;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async runNpm() {
|
|
366
|
+
const epoch = this.epoch;
|
|
367
|
+
const prev = this.npm;
|
|
368
|
+
const next = await readNpmSummary(this.root(), prev);
|
|
369
|
+
if (epoch !== this.epoch) return;
|
|
370
|
+
const changed =
|
|
371
|
+
prev &&
|
|
372
|
+
(prev.deps !== next.deps ||
|
|
373
|
+
prev.dev !== next.dev ||
|
|
374
|
+
prev.modules.stamp !== next.modules.stamp);
|
|
375
|
+
if (changed) {
|
|
376
|
+
const now = Date.now();
|
|
377
|
+
this.marks.npm = now;
|
|
378
|
+
this.mark(now, 'npm');
|
|
379
|
+
}
|
|
380
|
+
this.npm = next;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
runRuns() {
|
|
384
|
+
this.runs = readRuns(this.root());
|
|
385
|
+
this.noteRuns(this.runs);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
noteLoaded() {
|
|
389
|
+
if (!this.active) return;
|
|
390
|
+
const totals = fileTotals(fileEntries(this.ui.items));
|
|
391
|
+
const key = totalsKey(totals);
|
|
392
|
+
if (key === this.totalsKey) return;
|
|
393
|
+
const prev = this.totals;
|
|
394
|
+
if (prev) {
|
|
395
|
+
const added = totals.added - prev.added;
|
|
396
|
+
const removed = totals.removed - prev.removed;
|
|
397
|
+
const at = Date.now();
|
|
398
|
+
this.diffDelta = { added, removed, at };
|
|
399
|
+
const plus = Math.max(0, added);
|
|
400
|
+
const minus = Math.max(0, removed);
|
|
401
|
+
this.heat(at, plus || (minus ? 0 : 1), minus);
|
|
402
|
+
}
|
|
403
|
+
this.totals = totals;
|
|
404
|
+
this.totalsKey = key;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
requestAll() {
|
|
408
|
+
this.touch.add(UNKNOWN_PATH);
|
|
409
|
+
for (const task of Object.values(this.tasks)) task.request();
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
noteDisk(paths) {
|
|
413
|
+
if (!this.active) return;
|
|
414
|
+
const found = classify(paths);
|
|
415
|
+
if (found.all) return void this.requestAll();
|
|
416
|
+
const tasks = this.tasks;
|
|
417
|
+
if (found.files.length) {
|
|
418
|
+
for (const rel of found.files) this.touch.add(rel);
|
|
419
|
+
tasks.files.request();
|
|
420
|
+
}
|
|
421
|
+
if (found.git) tasks.git.request();
|
|
422
|
+
if (found.npm) tasks.npm.request();
|
|
423
|
+
if (found.runs) tasks.runs.request();
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
start() {
|
|
427
|
+
if (this.active) return;
|
|
428
|
+
this.clear();
|
|
429
|
+
this.active = true;
|
|
430
|
+
this.index = new FileIndex(this.root());
|
|
431
|
+
this.noteLoaded();
|
|
432
|
+
this.requestAll();
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
stop() {
|
|
436
|
+
this.epoch += 1;
|
|
437
|
+
this.active = false;
|
|
438
|
+
this.cancelTimers();
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
reset() {
|
|
442
|
+
this.stop();
|
|
443
|
+
this.clear();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
view() {
|
|
447
|
+
const ui = this.ui;
|
|
448
|
+
const now = Date.now();
|
|
449
|
+
const entries = fileEntries(ui.items);
|
|
450
|
+
const store = ui.review.store;
|
|
451
|
+
return buildModel({
|
|
452
|
+
now,
|
|
453
|
+
frame: ui.progressFrame,
|
|
454
|
+
busy: ui.ops.busy,
|
|
455
|
+
index: this.index,
|
|
456
|
+
fileDelta: this.fileDelta,
|
|
457
|
+
entries,
|
|
458
|
+
totals: this.totals ?? fileTotals(entries),
|
|
459
|
+
activity: this.activityView(now),
|
|
460
|
+
diffDelta: this.diffDelta,
|
|
461
|
+
git: this.git,
|
|
462
|
+
switches: this.switches,
|
|
463
|
+
branchAt: this.branchAt,
|
|
464
|
+
marks: this.marks,
|
|
465
|
+
npm: this.npm,
|
|
466
|
+
npmExtras: ui.lifecycle.npmExtras(),
|
|
467
|
+
npmRun: ui.npm.lastRun,
|
|
468
|
+
runs: this.liveRuns(),
|
|
469
|
+
notes: noteCounts(store),
|
|
470
|
+
store,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
packagesView() {
|
|
475
|
+
return npmModel({
|
|
476
|
+
npm: this.npm,
|
|
477
|
+
npmExtras: this.ui.lifecycle.npmExtras(),
|
|
478
|
+
npmRun: this.ui.npm.lastRun,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
packageCount() {
|
|
483
|
+
const data = this.packagesView();
|
|
484
|
+
if (!data.ready || !data.hasManifest) return 1;
|
|
485
|
+
const listed = data.modules && data.modules.packages;
|
|
486
|
+
return listed ? listed.length : 0;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
openPackages() {
|
|
490
|
+
const ui = this.ui;
|
|
491
|
+
ui.nav.pane = 'packages';
|
|
492
|
+
ui.nav.packagesCursor = 0;
|
|
493
|
+
ui.nav.resetListScroll('packages');
|
|
494
|
+
ui.nav.clearSelection();
|
|
495
|
+
ui.status = '';
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
showFiles(scope) {
|
|
499
|
+
const ui = this.ui;
|
|
500
|
+
ui.showFiles();
|
|
501
|
+
if (scope === 'file') filesPane.onFileScope(ui);
|
|
502
|
+
else filesPane.onDiffScope(ui);
|
|
503
|
+
ui.status = '';
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
open(id) {
|
|
507
|
+
const ui = this.ui;
|
|
508
|
+
const openers = {
|
|
509
|
+
files: () => this.showFiles('file'),
|
|
510
|
+
diffs: () => this.showFiles('diff'),
|
|
511
|
+
commits: () => ui.commits.onCommit(),
|
|
512
|
+
branches: () => ui.gitBranches.onBranch(),
|
|
513
|
+
npm: () => this.openPackages(),
|
|
514
|
+
run: () => ui.npm.open(),
|
|
515
|
+
tasks: () => ui.composer.tasks.openTasksPage(),
|
|
516
|
+
};
|
|
517
|
+
const opener = openers[id];
|
|
518
|
+
if (!opener || ui.mode !== 'review') return;
|
|
519
|
+
opener();
|
|
520
|
+
this.afterDraw();
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
enter() {
|
|
524
|
+
if (!this.active) return;
|
|
525
|
+
this.tasks.runs.request();
|
|
526
|
+
this.afterDraw();
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
module.exports = { Dashboard, classify, ageDelay };
|