aboutsummaryrefslogtreecommitdiffstats
path: root/web_src/js
diff options
context:
space:
mode:
authorNorwin <noerw@users.noreply.github.com>2021-01-21 14:51:52 +0000
committerGitHub <noreply@github.com>2021-01-21 15:51:52 +0100
commitb5570d3e680570343c1552bfc972b19b161209cd (patch)
tree548fbcdb9a760b47c54ac931c0180d87d08029d5 /web_src/js
parent56a89296050096df29d0a653019c194631cc6562 (diff)
downloadgitea-b5570d3e680570343c1552bfc972b19b161209cd.tar.gz
gitea-b5570d3e680570343c1552bfc972b19b161209cd.zip
Display current stopwatch in navbar (#14122)
* add notification about running stopwatch to header * serialize seconds, duration in stopwatches api * ajax update stopwatch i should get my testenv working locally... * new variant: hover dialog * noscript compatibility * js: live-update stopwatch time * js live update robustness
Diffstat (limited to 'web_src/js')
-rw-r--r--web_src/js/features/stopwatch.js91
-rw-r--r--web_src/js/index.js2
2 files changed, 93 insertions, 0 deletions
diff --git a/web_src/js/features/stopwatch.js b/web_src/js/features/stopwatch.js
new file mode 100644
index 0000000000..d500fb5f0f
--- /dev/null
+++ b/web_src/js/features/stopwatch.js
@@ -0,0 +1,91 @@
+import prettyMilliseconds from 'pretty-ms';
+const {AppSubUrl, csrf, NotificationSettings} = window.config;
+
+let updateTimeInterval = null; // holds setInterval id when active
+
+export async function initStopwatch() {
+ const stopwatchEl = $('.active-stopwatch-trigger');
+
+ stopwatchEl.removeAttr('href'); // intended for noscript mode only
+ stopwatchEl.popup({
+ position: 'bottom right',
+ hoverable: true,
+ });
+
+ // form handlers
+ $('form > button', stopwatchEl).on('click', function () {
+ $(this).parent().trigger('submit');
+ });
+
+ if (!stopwatchEl || NotificationSettings.MinTimeout <= 0) {
+ return;
+ }
+
+ const fn = (timeout) => {
+ setTimeout(async () => {
+ await updateStopwatchWithCallback(fn, timeout);
+ }, timeout);
+ };
+
+ fn(NotificationSettings.MinTimeout);
+
+ const currSeconds = $('.stopwatch-time').data('seconds');
+ if (currSeconds) {
+ updateTimeInterval = updateStopwatchTime(currSeconds);
+ }
+}
+
+async function updateStopwatchWithCallback(callback, timeout) {
+ const isSet = await updateStopwatch();
+
+ if (!isSet) {
+ timeout = NotificationSettings.MinTimeout;
+ } else if (timeout < NotificationSettings.MaxTimeout) {
+ timeout += NotificationSettings.TimeoutStep;
+ }
+
+ callback(timeout);
+}
+
+async function updateStopwatch() {
+ const data = await $.ajax({
+ type: 'GET',
+ url: `${AppSubUrl}/api/v1/user/stopwatches`,
+ headers: {'X-Csrf-Token': csrf},
+ });
+
+ if (updateTimeInterval) {
+ clearInterval(updateTimeInterval);
+ updateTimeInterval = null;
+ }
+
+ const watch = data[0];
+ const btnEl = $('.active-stopwatch-trigger');
+ if (!watch) {
+ btnEl.addClass('hidden');
+ } else {
+ const {repo_owner_name, repo_name, issue_index, seconds} = watch;
+ const issueUrl = `${AppSubUrl}/${repo_owner_name}/${repo_name}/issues/${issue_index}`;
+ $('.stopwatch-link').attr('href', issueUrl);
+ $('.stopwatch-commit').attr('action', `${issueUrl}/times/stopwatch/toggle`);
+ $('.stopwatch-cancel').attr('action', `${issueUrl}/times/stopwatch/cancel`);
+ $('.stopwatch-issue').text(`${repo_owner_name}/${repo_name}#${issue_index}`);
+ $('.stopwatch-time').text(prettyMilliseconds(seconds * 1000));
+ updateStopwatchTime(seconds);
+ btnEl.removeClass('hidden');
+ }
+
+ return !!data.length;
+}
+
+async function updateStopwatchTime(seconds) {
+ const secs = parseInt(seconds);
+ if (!Number.isFinite(secs)) return;
+
+ const start = Date.now();
+ updateTimeInterval = setInterval(() => {
+ const delta = Date.now() - start;
+ const dur = prettyMilliseconds(secs * 1000 + delta, {compact: true});
+ $('.stopwatch-time').text(dur);
+ }, 1000);
+}
diff --git a/web_src/js/index.js b/web_src/js/index.js
index 541f32507d..9a35507bab 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -22,6 +22,7 @@ import createDropzone from './features/dropzone.js';
import initTableSort from './features/tablesort.js';
import ActivityTopAuthors from './components/ActivityTopAuthors.vue';
import {initNotificationsTable, initNotificationCount} from './features/notification.js';
+import {initStopwatch} from './features/stopwatch.js';
import {createCodeEditor, createMonaco} from './features/codeeditor.js';
import {svg, svgs} from './svg.js';
import {stripTags} from './utils.js';
@@ -2626,6 +2627,7 @@ $(document).ready(async () => {
initProject(),
initServiceWorker(),
initNotificationCount(),
+ initStopwatch(),
renderMarkdownContent(),
initGithook(),
]);