Beeminder Forum

I made an online version of TagTime

Hi there! I’ve been working on a new open-source, web-based version of TagTime, called TagTime Web (my demo instance, but you can and should run your own instance) (source code). It’s basically just TagTime, but online. It supports the Web Notifications API, so you can get a push notification when a ping occurs (Web Notifications aren’t supported by iOS Safari yet, though). You can also have it play a sound when it is ping time. On devices that support it the device will vibrate when it is ping time (untested, since my phone doesn’t support it and I can’t feel vibration on emulators (if your phone supports it: is the vibration too long?)).

You can import or export from a TagTime log file, and export (but not easily import) the internal SQLite database used to represent your pings.
Some other neat features include

  • Fast loading times (it doesn’t need to sync your entire ping history to the browser)
  • Tag autocomplete
  • Custom interval/seed
  • Each tag gets a unique colour based on the hash of it’s name
  • Tags are converted to lowercase
  • Dark mode and light mode
  • Edit pings without needing to load your entire ping history in the Pings tab (you can view pings in a time range, and thanks to server-side pagination you don’t need to download everything at once) (currently the Pings tab might have a few size issues on mobile, I’m working on improving tag input on smaller screens)
  • It works on most modern browsers on both desktop and mobile
  • It works offline (although if you answer pings differently on different devices one answer will overwrite the other)
  • You can add it to the homescreen and use it like an app (it’s a PWA)

It uses a new ping algorithm that determines the seeded FNV-1A hash of the current Unix time in seconds as a 0-1 fraction, and pings on a second if that second’s fraction is less than reciprocal of the interval in seconds. (source code for this is in the taglogic directory)

The frontend and backend logic is written in JavaScript and TypeScript, the frontend UI is written in Svelte, the ping algorithm is written in Rust and compiled to WASM. The source code is on Github. (be warned: the code is a bit messy in some places for now).

There are currently a few important issues:

  • It doesn’t support older browsers. (If this causes problems tell me what browser version you are trying with and I might be able to add support for it.)
  • It silently fails if you use more than 40 MiB (if you host it yourself you can change the limit in the config.json file)

I intend to add more features to TagTime Web over time, including adding some graphs and more features.

Thanks for reading, let me know what you think of this!

8 Likes

Hi there! I’ve made some updates recently. Here they are:

  • Version numbering in the footer. If you see “v53” (or higher, if you are from the future) at the start of the footer, then you have these updates. If you haven’t got them, reload, close all open TTW tabs and re-open them. This should force an update.
  • Better ping filtering, used on the Pings page and on graphs. Now you can specify if all the tags you specify should be included, or just one.
  • Bug fixes for pagination in the pings page
  • Added an indicator to show if pings are synced
  • A graphs page, based off these ones
  • Made a demo video (slightly outdated)

I’m currently working on adding more graphs and an integrated todo list.

Here are some graphs it can generate (you might want to disable pagination when generating graphs to get all data ever, or set a time range):

2 Likes

Awesome work! Any chance you’d consider the official TagTime universal ping schedule?

2 Likes

I’ve added support for the universal ping schedule. There is now a button in Settings to use it (make sure you see v60 (or higher) in the footer, if not try closing your browser and re-opening it (or just closing all TTW tabs, waiting a few seconds, and re-opening them (or just clearing your cache))):

"Use the universal schedule" button

Note that due to the way I’ve implemented it, if you are using the original TagTime algorithm but not the universal schedule (different seed/interval (seed+algorithm are configured under Advanced)) then it will be slower. (This is because I’ve pre-generated a lookup table for each 5 day interval for the universal schedule. When on the universal schedule instead of starting from URPING it maps the earliest time it cares about to an index in the lookup table, and populates the RNG state based on that, for more details see the Rust source code).

If you any more suggestions, please tell me!

2 Likes

A note about your comment on line 85:

That’s not actually considered a compiler bug. That line is indeed unused, when your code is compiled normally (not compiled in test mode.) The way to avoid that warning is to tell the compiler not to bother compiling that module in test mode—that is, put a #[cfg(test)] before the module, on line 82.

That’s actually the main reason why tests are generally put in their own module to begin with—you could put the tests at the top level without the mod test block, but then you wouldn’t have anywhere to put the #[cfg(test)] attribute! You want to have the attribute not just because it avoids the unused code warning, but also because it saves you compile time, telling the compiler to skip that module entirely.

(Also, it saves you space in the compiled binary—it’s rather pointless to have the tests compiled and included in the resulting binary even when they aren’t run.)

One could imagine an alternate universe where the compiler tries to “do what you mean” and does the equivalent of adding that attribute to your test module for you. But the Rust compiler as it stands doesn’t do that, and for what I think are good reasons. Explicit is better than implicit, or the anti-magic principle, for one. You don’t want the compiler doing “magic” based on circumstantial facts like the name of the module (test is just conventional, it’s not special cased), or the fact that the module contains only tests (because the second you add a helper function for your tests, the behavior would silently change.) It’s a very good thing that the Rust compiler has chosen to act consistently—all functions in all modules are compiled, unless you specify conditional compilation with #[cfg()] (or #[cfg_attr()]). This lets you have confidence that you know exactly what’s being compiled (and what goes into the resulting binary) without any guesswork, or any weird rules you have to memorize.

All this is the long way to say: just add #[cfg(test)] to line 82, and you can remove line 84 and the comment on line 85, and the issue there will go away.

3 Likes

Thanks, I’ve fixed it.

2 Likes

Here’s another update:

  • You have been logged out due to a authentication revamp, because…
  • You can change your password now (and also /.well-known/change-password is supported on the backend server (unlike Beeminder btw))
  • The homepage you get when you are logged out now has content (instead of 1 line of text that kinda explains it)
  • Updated dependecies
  • There is now a warning that your email address in un-changeable
  • The main content is now in a semantically correct <main> tag
  • Bugfix: sometime between now and last deploy it errored when built in production mode, which turned out to be an upstream bug (with svelte-loader) that I that I fixed
  • Bugfix: sometimes notifications would stop arriving
  • Bugfix: notifications came at the wrong time if you were using the original scheduling algorithm
  • Bugfix: there used to be a memory leak that leaked memory but very slowly (it only started to be an issue after running the server for more than a day or two), but I think I’ve gotten rid of it

If you have any issues or features you want, please tell me!

2 Likes