Age | Commit message (Collapse) | Author | Files | Lines |
|
I'm attempting to maintain a top-level secrets.json that defines all of the
sensitive data that I'd like to version-control without exposing everything in
cleartext to the world. To that end, I'm using `git secret`, which will use
`gpg` to encrypt secrets.json everytime I call `git secret hide` and decrypt
everytime I call `git secret reveal`.
I'm going to try this until I don't like it anymore... if that day comes...
I should write a blog post about my setup to solicit useful feedback and share
my ideas with others.
|
|
In the spirit of Marie Kondo, I'm tidying up!
TL;DR:
- Prefer .envrc `use_nix` and delete all dir-locals.nix files
- Remove ~all references to <nixpkgs>, <unstable>, <depot> and prefer
referencing each with briefcase.third_party.{pkgs,unstable,depot}
- Delete nixBufferFromShell function since I was only using that in
dir-locals.nix files
|
|
Disabling failing packages until I can get a working CI build.
|
|
Unforeseen problem: `buildkite-agent` runs its builds in a separate directory,
so if I want the `nix-build` command to build the newly checked out code, I need
to set <briefcase> to the CWD.
|
|
I've encountered a few problems with attempting to support nixos-rebuild:
- the activation step requires `sudo` privileges
- the `buildkite-agent` runs on the same machine, socrates, that is rebuilding
itself. This means that when the activation step runs, it will attempt to
restart `buildkite-agent` when the agent is still working
I'm slowly removing places in my nix code that rely on '<bracket>' notation, so
that I no longer depend on NIX_PATH being set. I still have more work to do.
{covid-uk,sandbox}/default.nix are breaking when I attempt to run my
build-socrates.sh script locally, so I'm temporarily disabling them until I can
get CI working as I expect.
|
|
I'm still unsure whether or not this is a good idea, but experimenting is a good
way to find out!
|
|
TL;DR:
- Adds string-conversions library
- Adds tests for remaining units and repeating requests
- Adds a REPL in main
|
|
Parse inputs like -10s into 10 second shifts back in time.
|
|
Interact with Stripe's payment_intents API endpoint.
I'm not committing the index.html that contains client-side code that interacts
with the /create-payment-intent endpoint, but it contains sensitive information,
so I'm omitting it for now.
TL;DR:
- Define POST /create-payment-intent endpoint
- Include envStripeAPIKey in Context record
- Define a top-level Stripe module for making API calls
- Define types and instances that align with Stripes request and response types
- Depend on the Req library: a higher-level library than http-client
|
|
Use the newly defined `buildHaskell` function for a few of my existing Haskell
projects. So far, it works as intended!
|
|
After burning a few hours wrestling with the type system, I decided to revert to
the simpler `Server API` type instead of the `ServantT` transformer type.
The problem is that I couldn't write a MonadError instance for `RIO Context`,
which is my `AppM` (i.e. application monad). Using `throwIO` in the server
handlers results in 500 errors, which is not what I wanted. I'm still pretty
fuzzy about what's happening; I now know that exception handling in Haskell is
pretty gnaryly. I may revisit this at a later time when my knowledge is more
extensive. For now: time to fry bigger fish.
An easier abstract is for me to pass `T.Context` into `server` as an argument,
which after all is what a Reader does.
TL;DR:
- Read server, client ports from .envrc
- Define a top-level Failure type (empty for now)
- Define a top-level Success type
- Define App as RIO Context (Either Failure Success)
|
|
Long story -> short: I'd like to access my App monad from within my Servant
handlers.
While this code type-checks, I'm not sure it's working as intended. Needing to
change throwError to throwIO fails the "smell test". I expect to refactor this
code, but I'm calling it a night for now.
|
|
I believe RIO stands for: "ReaderT <something-something> IO", which is a nod to
the top-level application data type:
```haskell
-- This is a simplification
newtype RIO env a = RIO { runRIO :: ReaderT env a () }
```
I read about RIO from an FP-Complete blog post a few months ago, and now I'm
excited to try it out for a real project. Bon voyage!
|
|
I'm getting tired of:
```shell
$ cd <project-root>
$ nix-shell
$ cd src/server
$ ghci Main.hs
```
Instead:
```shell
$ cd <project-root>/src/server
$ ghci Main.hs
```
|
|
Defining a few tables in init.sql to sketch a few records that I need to
persist.
|
|
As the previous commit mentions, I'm attempting to build and deploy this project
with `nix-shell` and `nix-build` instead of `cabal` and `stack`.
I'm in the Hamburg airport right now, and my internet connection isn't stable
enough to test this, so I'm committing it until I can more robustly test it.
|
|
I'd like to see if I can avoid using `cabal` and `stack` and build and deploy
this application using `nix-shell` and `nix-build` only. Let's see how that
goes.
|
|
TL;DR:
- Consume GoogleSignIn.validateJWT in the Handler for /verify
- Rename validation fn to validateJWT
- Prefer Text to String type
|
|
Assert that the exp field of the JWT is "fresh".
|
|
The JWT should match "accounts.google.com" or "https://accounts.google.com". If
it doesn't, we produce a validation error.
TL;DR:
- Group all failed stringOrURI function calls as StringOrURIParseFailure errors
|
|
The subject of this commit message says it all.
|
|
Test that when the JWT contains the client ID for my Google app, the JWT is
valid, and when it doesn't, it's invalid.
|
|
I need IO for:
- Getting the current time to validate `exp`
- Making an HTTP request to Google's token verifier endpoint
|
|
Thank you, -Wall. You are truly an unsung hero.
|
|
I'm attempting to be an obedient boy and implement this and future features
using TDD.
TL;DR:
- Defined a few tests
- Defined an empty GoogleSignIn module
- Defined a Fixtures module to quickly create JWTs to test
|
|
Dumping grounds for personal, stylistic functions intended to improve readabily
and writability (in that order).
|
|
TL;DR:
- Add common dependencies like Servant, Aeson, Warp, Cors
- Define a POST /verify endpoint for our client to hit
- POST to /verify client-side onSignIn
|
|
TODO: Support Google Sign-in server-side
Also:
- Add Haskell to project's shell.nix
- Add stubbed Main.hs and Spec.hs
- Add common .ghci file
|
|
I'm particularly excited about this idea. As I was reading Graham's "Erase your
darlings" blog post, I had an idea: I should have playbooks at the root of my
monorepo.
I can have playbooks for the following:
- How to install NixOS
- How to build GCR images from Nix expressions
- A collection of miscellaneous shell commands (e.g. "how to kill a process by name")
- What series of steps should I follow when I receive a paycheck
I already keep README's at the root of each package, which I think is where many
of these instructions belong. Other tutorials that I write for myself that do
not belong to any package can go in //playbooks. I also will host my personal
habits in //playbooks since habits are a bit like playbooks for life. Let's see
how this idea ages as the caffeine wears off...
|
|
Thanks to the Nix anti-patterns documented here...
https://nix.dev/anti-patterns/language.html#reproducability-referencing-top-level-directory-with
...I'm cleaning up some of my Nix expressions. Read the article for more
context.
|
|
I often debug by changing the values of State.Model in the State.init
function. I usually revert these these chage; this time I didn't.
|
|
I incorrectly modelled all of the G-sharps in my application as belonging to the
G pitchClass, which resulted in a strange bug where vieChord printed "G minor
Root position", but the Piano highlit a G minor.
I checked the other accidentals, and it looks like everything is properly
classified.
|
|
I'm sure this app contains more unused code. I would like to find some Elm tools
for detecting and deleting dead code, but this isn't my current priority.
My current priority is dogfooding this app until I find it genuinely useful for
myself.
|
|
Whoops...
|
|
This is a temporary solution. Ideally I would like to handle this with the
following:
- Show the flashcard for a chord shortly after beginning a practice session
- Display a small 3...2...1... countdown timer immediately after beginning a
practice session
I need to dig more deeply into Elm's Time module and subscriptions to better
understand how to properly solve this problem. In the meantime, please tolerate
this short-term solution.
|
|
Allow users to include or exclude chord inversions.
|
|
For now, I'd like to support selecting keys and whitelisting inversions.
|
|
My much anticipated feature: first prompt the user for a name of a chord, then
show the user that chord.
Cascading changes:
I changed the "Tap to practice" overlayButton's opacity from 30% to 100% because
pausing when showFlashCard is True causes the two piece
TIL:
You can batch Elm Subscriptions using the Sub.batch function.
What I haven't learned yet:
How to best handle rotating screens for mobile devices (i.e. portrait
vs. landscape modes). In time...
What's left?
- Support sound
- Support a fine-tune section of the preferences
- Support tablet and web browser variants
- Ask users for the "I chord" instead of asking "C major Root position"
- More styling (of course)
|
|
Moving the UI.tw function into Tailwind.use. Creating and consuming some
functions like Tailwind.if_ and Tailwind.when to make it easier to conditionally
style some of my components.
|
|
Now the "Tap to practice" button fully covers the screen.
- Dropped support for a Piano direction (for now)
- Using w-full and w-1/2 for piano key "length"
|
|
TL;DR: scale down UI for non-mobile devices.
I pulled the screen resolution for my phone, the Google Pixel 4, off of the
internet. I created a device profile in Chrome to develop this application
specifically for my phone. To my surprise, when I opened the app on my phone,
many of elements that looked good in Google Chrome, looked askew on my phone. I
needed to troubleshoot.
Here's how I did that:
I used Tailwind to responsively color the bg for each breakpoint to see if my
device was sm, md, lg, xl (according to Tailwind's breakpoint
terminology). After reading Tailwind's documentation and comparing their
breakpoints with my Pixel 4's width (i.e. 1080px), I figured that my device
would be lg. It's not; it's md, which I confirmed by using ngrok to load
localhost:8000 on my phone and see that the background-color was
"md:bg-green-600".
I'm still unsure why my device is not lg, but knowing that my device was md
was enough to fix many of the styling issues. My current theory is that while
my screen's resolution is 1080 wide, the pixel density affects the media query
for the breakpoint.
|
|
This helps us avoid showing a chord from a key that the user did not whitelist.
|
|
Removing more unused code attempting to focus this app's scope.
|
|
Refactor the Piano component to highlight the root note of each chord. If this
makes things too easy, I can support this as a preference.
Also:
- Reduced the number of keys that the piano displays and increased the key
thickness to reclaim the space
- Preferred using Tailwind selectors instead of inline styling where applicable
- Call List.reverse on the keys to ensure that the top-most note is a lower note
than the bottom-most note
TODO:
- Support showing only the name of the chord and not just the notes that
comprise that chord
- Rewrite the function that generates the chords for a given range of notes
- Consider supporting a dark mode
|
|
Google Chrome's device preview doesn't resemble what I see when I use my phone
to visit this page.
|
|
Since I've published this, I should include an Overview page to orient potential
users. This Overview could be better -- as could many things with this app --
but it's a start, and I'm seeking small wins.
|
|
I mention setting tempo twice... whoops.
|
|
I'm preferring the verb "tap" to "press".
|
|
Observed problem: Tapping "C major, A minor" key, which LPC sets by default,
does not unset it.
Bug: handleClick passed the relativeMinor Key but the default value in
State.Model is the C Major key. We would toggled b/w [Cmajor] ->
[Cmajor,Aminor], and because toggled checked if either Cmajor or Aminor was
present, it was always true.
Solution: Check relativeMajor to set toggled.
|
|
Now that I have a deployed an MVP of my app, I am tidying things up to support
the next phase of development.
TL;DR:
- Moved application Model-related code into State module
- Moved each View into its own module
- Deleted unused ChordInspector component
- Deleted unused Msg's, {Increase,Decrease}Tempo
- Deleted misc unused code
|