beancount/fava

Allow ISO Formatted string dates in charts svelte-component

mattmccormick opened this issue · 3 comments

I'm trying to write a Fava extension. The extension would display a line chart using the following code:

{% set chart_data = [{'type': 'balances', 'label': 'Chart', 'data': extension.data()}] %}

<svelte-component type="charts">
    <script id="chart-data" type="application/json">{{chart_data|tojson}}</script>
</svelte-component>

The issue is that the LineChartDatum must be a native JS Date object

readonly date: Date;

However, it is not possible to use a date string as the component will fail with the following error:

Rendering component 'charts' failed due to invalid JSON data:

Parsing of data for balances chart failed:
Validating object failed at key 'date': Expected a date

Allow ISO Formatted string dates in charts svelte-component

That is already the case - JSON data is loaded via validators, which try to convert from e.g. a string to a Date. The error comes from the function

export const date: Validator<Date> = (json) => {
which tries exactly that.

Can you provide some example data that fails loading?

Here's a test plugin that should reproduce the issue.

test_plugin/templates/TestPlugin.html

{% set chart_data = [{'type': 'balances', 'label': 'Chart', 'data': extension.data()}] %}

<svelte-component type="charts">
    <script id="chart-data" type="application/json">{{chart_data|tojson}}</script>
</svelte-component>

test_plugin/__init__.py

from datetime import datetime

from fava.ext import FavaExtensionBase


class TestPlugin(FavaExtensionBase):
    report_title = 'Test Plugin'

    def data(self):
        return [
            {
                'name': 'Chart',
                'values': [
                    {'name': 'Value', 'date': datetime.now().isoformat(), 'value': 2}
                ]
            }
        ]

In the .beancount file, add:

2000-01-01 custom "fava-extension" "test_plugin"

When clicking on the Test Plugin link in the left side navbar, the page should display the following error:

Rendering component 'charts' failed due to invalid JSON data:
Parsing of data for balances chart failed:
Validating object failed at key 'date': Expected a date

The generated HTML should be:

<svelte-component type="charts">
    <script id="chart-data" type="application/json">[
  {
    "data": [
      {
        "name": "Chart",
        "values": [
          {
            "date": "2024-05-26T09:05:12.097824",
            "name": "Value",
            "value": 2
          }
        ]
      }
    ],
    "label": "Chart",
    "type": "balances"
  }
]</script>

A date is expected there, not a datetime - so calling date() on that datetime before serialising it should do the trick. In theory, so far anything the Javascript Date constructor accepted would have worked, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#date_time_string_format - due to the timezone inconsistencies in parsing though, that's not really desirable, I'll tighten the validation there.