Files: 1006d0c4dde00ee503cde396de716125b96524c1 / lib / depject / app / html / progress-notifier.js
4445 bytesRaw
1 | const { computed, when, h, Value } = require('mutant') |
2 | const nest = require('depnest') |
3 | const sustained = require('../../../sustained') |
4 | const pull = require('pull-stream') |
5 | |
6 | exports.gives = nest('app.html.progressNotifier') |
7 | |
8 | exports.needs = nest({ |
9 | 'sbot.pull.stream': 'first', |
10 | 'progress.obs': { |
11 | indexes: 'first', |
12 | replicate: 'first', |
13 | migration: 'first' |
14 | }, |
15 | 'intl.sync.i18n': 'first' |
16 | }) |
17 | |
18 | exports.create = function (api) { |
19 | const i18n = api.intl.sync.i18n |
20 | return nest('app.html.progressNotifier', function () { |
21 | const replicateProgress = api.progress.obs.replicate() |
22 | const indexes = api.progress.obs.indexes() |
23 | const migration = api.progress.obs.migration() |
24 | const waiting = Waiting(replicateProgress) |
25 | |
26 | const pending = computed(indexes, (progress) => progress.target - progress.current || 0) |
27 | const pendingMigration = computed(migration, (progress) => progress.target - progress.current || 0) |
28 | |
29 | const indexProgress = computed(indexes, calcProgress) |
30 | const migrationProgress = computed(migration, calcProgress) |
31 | |
32 | let incompleteFeedsFrom = 0 |
33 | |
34 | const downloadProgress = computed([replicateProgress.feeds, replicateProgress.incompleteFeeds], (feeds, incomplete) => { |
35 | if (incomplete > incompleteFeedsFrom) { |
36 | incompleteFeedsFrom = incomplete |
37 | } else if (incomplete === 0) { |
38 | incompleteFeedsFrom = 0 |
39 | } |
40 | if (feeds && incomplete) { |
41 | return clamp((feeds - incomplete) / incompleteFeedsFrom) |
42 | } else { |
43 | return 1 |
44 | } |
45 | }) |
46 | |
47 | const hidden = sustained(computed([waiting, downloadProgress, pending, pendingMigration], (waiting, downloadProgress, pending, pendingMigration) => { |
48 | return !waiting && downloadProgress === 1 && !pending && !pendingMigration |
49 | }), 500) |
50 | |
51 | // HACK: css animations take up WAY TO MUCH cpu, remove from dom when inactive |
52 | const displaying = computed(sustained(hidden, 500, x => !x), hidden => !hidden) |
53 | |
54 | // HACK: Resolves an issue where buttons are non-responsive while indexing. |
55 | // |
56 | // 1. Sets the *progress* cursor when Patchwork is focused. |
57 | // 2. Sets the *wait* cursor when a publish button is selected. |
58 | // 3. Sets the *not-allowed* cursor when a publish button is activated. |
59 | // |
60 | // If a user disregards all of the above then `modules/sbot.js` will return |
61 | // an error telling the user to wait until indexing is finished. |
62 | const readOnlyMode = ` |
63 | body { |
64 | cursor: progress; |
65 | } |
66 | |
67 | button:not(.-clear):not(.-cancel):not(.cancel), .like, .reply, .tag, .ToggleButton, .Picker { |
68 | cursor: wait; |
69 | opacity: 0.5; |
70 | } |
71 | |
72 | button:not(.-clear):not(.-cancel):not(.cancel):active, .like:active, .reply:active, .tag:active, .ToggleButton:active, .Picker:active { |
73 | cursor: not-allowed; |
74 | } |
75 | ` |
76 | |
77 | return h('div.info', { hidden }, [ |
78 | h('div.status', [ |
79 | when(displaying, h('Loading -small', [ |
80 | when(pendingMigration, |
81 | [h('span.info', i18n('Upgrading database')), h('progress', { style: { 'margin-left': '10px' }, min: 0, max: 1, value: migrationProgress })], |
82 | when(computed(downloadProgress, (v) => v < 1), |
83 | [h('span.info', i18n('Downloading new messages')), h('progress', { style: { 'margin-left': '10px' }, min: 0, max: 1, value: downloadProgress })], |
84 | when(pending, [ |
85 | [ |
86 | h('span.info', i18n('Indexing database')), |
87 | h('progress', { style: { 'margin-left': '10px' }, min: 0, max: 1, value: indexProgress }), |
88 | h('style', readOnlyMode) |
89 | ] |
90 | ], i18n('Scuttling...')) |
91 | ) |
92 | ) |
93 | ])) |
94 | ]) |
95 | ]) |
96 | }) |
97 | |
98 | // scoped |
99 | |
100 | function Waiting (progress) { |
101 | const waiting = Value() |
102 | let lastTick = Date.now() |
103 | |
104 | progress && progress(update) |
105 | |
106 | pull( |
107 | api.sbot.pull.stream(sbot => sbot.patchwork.heartbeat()), |
108 | pull.drain(update) |
109 | ) |
110 | |
111 | setInterval(function () { |
112 | if (lastTick < Date.now() - 1000) { |
113 | waiting.set(true) |
114 | } |
115 | }, 1000) |
116 | |
117 | return waiting |
118 | |
119 | // scoped |
120 | |
121 | function update () { |
122 | lastTick = Date.now() |
123 | waiting.set(false) |
124 | } |
125 | } |
126 | } |
127 | |
128 | function clamp (value) { |
129 | return Math.min(1, Math.max(0, value)) || 0 |
130 | } |
131 | |
132 | function calcProgress (progress) { |
133 | const range = progress.target - progress.start |
134 | if (range) { |
135 | return (progress.current - progress.start) / range |
136 | } else { |
137 | return 1 |
138 | } |
139 | } |
140 |
Built with git-ssb-web