There is no point in creating a new invoice without products, thus we
were forcing users to always use the “Add product” button for no reason
other than it was easier for me….
I wanted to add the product inside ServeInvoice, when the slug is “new”,
but then it tried to compute the invoice total without price or quantity
and it failed. Thus, i add that product after it has done the
computation query.
I tried this already when i started adding filters, but i tried to use
AlpineJS for that, and could not because it would reset the context each
time i submitted the filters, due to HTMx replacing the whole content.
I realized that the only thing i need is some “flag” to show and hide
the form with CSS. I do not even need AlpineJS for that, but i used it
anyway because then i can use the x-cloak thing to hidde the toggle
button for users with JavaScript disabled.
Similarly, the body by default has that “flag” set in the markup, and is
removed when AlpineJS is initialized, thus if JavaScript is disabled the
filters form is shown nevertheless.
That column was supposed to have a checkbox for batch operations, but
we do not have any operation that would like to perform to many products
or contacts at the same time. For now, at least.
I want the `white-space: pre` to preserve the newline characters that
users may have used, but this prevents line wrapping and long lines are
not confined within the page margins.
`pre-line` preserves the newlines, but collapses spaces and tabs, and
wraps long text, which is more what i want.
For some reason, i assumed that if the invoice product has and ID, that
is it comes from the database, it must also have a product ID, which is
incorrect, because we allow invoice lines with products not added to the
product relation.
I am using zero to mean “no product ID”, so now that validation has to
include the zero as well.
Otherwise, pgx (rightfully) tries to convert a "" into a integer, as
this is the field’s type, cannot, and panics with an error.
Added a IntegerOrNull method to FormField because this is exactly the
same that happens with the invoiceProductId, and made no sense to have
to do the logic twice, or in a function inside form.
Oriol told me what he actually wants: a way to see the current month,
quarter, and year for both double-check that the taxes form are filled
in correct and to see whether the business is doing well. This is
specially important for the quarter period, as he has to fill taxes
each quarter. Thus, the “last 90 days” thing i did was easier for me,
but completely useless for him.
We also decided to add previous month and previous quarter options
because it would be unfair to expect users check that data exactly the
last day or “lose access” to it.
I had to change MethodOverrider to check whether the form is encoded as
multipart/form-data or i would not be able to get the method field from
forms with files.
For now i add the file manually, i.e., outside add_expense and
edit_expense PL/pgSQL functions, because it was faster for me, but i
will probably add an attach_to_expense function, or something like that,
to avoid having the whole ON CONFLICT logic inside Golang—this belongs
to the database.
It is a separate table because we allow expenses to not have such an
attachment, although we allow only an attachment per expense, and i do
not want to have a bunch of nullable columns for that.
I decided to keep the files in the database, contrary to “conventional
wisdom” of storing files in the filesystem, because these attachments
are invoices and such documets that are an integral part of the expense
relation. In other words, losing these files would render the expense
(almost) useless. Thus, the ACID guarantees of the database are the
most appropriate place for them.
I was hit with a couple of bugs: hx-on not properly de-initializing,
with a workaround in 43fffb68 and properly fixed with version 1.9.2;
and elements with naked hx-trigger did not work with hx-boost, as i do
for the tag inline form, fixed in 1.9.1.
The other bug fixed in 1.9.1, play well with other libraries that also
use the window.onpopstate, did not affect me, i believe.
By chance, i found out that sometimes Go returned a Content-Type header
of text/plain for some responses to HTMx request. Go’s documentation
for http.ResponseWriter.Write sheds some light to this issue:
> If the Header does not contain a Content-Type line, Write adds a
> Content-Type set to the result of passing the initial 512 bytes of
> written data to DetectContentType.
http.DetectContentType has “sniff signatures” for the most common HTML
elements, such as `<BODY`, `<P`, or even `<!--`, but when the template
only has elements not in that list, the text “text sniff signature”
kicks in because the content does not contain binary data bytes, as
specified in [0], §7.1, step 9.
I can not change mustRenderTemplate’s wr parameter, and its callers’,
to be of type http.ResponseWriter because mustWriteInvoicePdf writes
the template to a pipe object, which is not of this type. Thus, i have
to resort to type assertion inside the method.
[0]: https://mimesniff.spec.whatwg.org/#identifying-a-resource-with-an-unknown-mime-type
They are almost the same as for the multiselect, except that it “clicks”
the option to “select” it, as this will trigger the replacement of the
<fieldset> with the whole product.
I had a lot of errors when trying to swap an element that has data-hx-on
attribute: it would tell me that it could not swap the bloody thing and
that t.onHandlers is not an iterable. I believe it also happened for
elements that did not have data-hx-on, but i am unsure at this point.
Apparently this is a bug introduced with version 1.9.0 of HTMx that as
of today is not yet fixed[0].
It seems that the problem that they keep the handlers created by
data-hx-on in an object, to be able to remove them afterward, but they
were looping the object with for(… of …) instead of for(… in …).
They will surely fix it in time, but since they will release a new
version, i have decided to change the minified code for now, as there
is no danger of replacing it with the new version—different file names.
[0]: https://github.com/bigskysoftware/htmx/issues/1368