goby.garden
goby is a work-in-progress desktop application. this page is inspired by broadsheet, and tracks my live progress through various notetaking contexts. ā Nico
Currently I describe goby as an interface for creating and managing personal databases. Compared to existing tools that fall under that umbrella, I want Goby to prioritize things like personal data ownership, durable and transparent file format (SQLite), and referential compatibility with assets stored in different places (desktop files, web URLs, raw text, etc).
goby journal
[src]
1/27/2025
Iāve previously come to the conclusion that it would be pretty difficult to support ordered lists for relation properties with my SQL model - I wonder if I could do it via the method detailed here though, just adding two _order
columns to the junction table (one for each side), and enforcing the order when I save to the database...
1/6/2025
Another big change that I have planned is moving the property definitions to their own tables, instead of defining them in a JSON field.
goby-database/notes.md
[src]
Contents:
...and more below
Running notes
1/18/2025
Picking up on the reflection from the 16th: Iāve taken care of cases where transfers get queued for nonexistent targets, and general duplicate actions, by filtering those out in the consolidation step. The open question is what to do when someone deletes a property which was previously a target, and then adds their own new target within the same class. Normally when you delete a property which was a target, I queue the creation of a one-way relation to replace it, and transfer the connections from the previous two-way.
Itās an open question whether to keep that behavior at all, since I could imagine the function just deleting everything that involves deleted targets, with no attempts at preserving data. Likely the interface will automatically handle some of this anyway, and send an input that takes it into account. But on the other hand I think it is nice, especially if someone uses the class as a programmatic interface (not that I necessarily see that happening, but maybe if this project miraculously takes off). So I think Iāll leave it in, and in the future what I could do is make that an option, e.g. "safe mode", set to true/false, that way you can bypass it if you prefer.
What Iād like to do though, since this problem is about validation with other relationship edits, is to address it in the consolidation function. And I think I have a way to accomplish that: when consolidating, if there are multiple creations/transfers involving the same pair of classes and one matching property, pick the one with the highest level of specificity, meaning privilege prop targets to class targets.
1/16/2025
- I think I need to modify my logic for deleting or creating relations on the basis of classes/properties being deleted
- e.g. if I delete a property, but rather than targeting the whole class, I already have a change queued to move the target to a different property. In that situation, it should honor whatās already in the queue instead of queing or overriding another transfer
- also, what happens if the classes on either side of a relation are deleted? there may technically be available transfers individually, but they cancel each other out. I need to make sure the classes and properties in new_sides, exist, otherwise reject a transfer and just delete.
1/13/2025
Current to-do:
- refactor junctions so that:
- in the junction list, the following are normalized: side_a_class_id, side_a_prop_id, side_b_class_id, side_b_prop_id
- should be retrieved as a JunctionSides json array
- in individual junctions, the columns should be a little more descriptive, e.g. class_2_property_5 or class_3
- in the junction list, the following are normalized: side_a_class_id, side_a_prop_id, side_b_class_id, side_b_prop_id
- refactor properties so they exist in their own tables, and are created when classes are created
- refactor class/junction retrieval and caching
- reflect above changes
- separate retrieval of items, properties, and relations
- get relation targets from junction list rather than storing them on the property (DRY)
- implement junction transfer
- take a pass at unifying/clarifying the terminology a little bit
- maybe replace "junction" with "relationship" and "relation" with "connection"?
Currently working through revising the edit schema function. The class and prop edit loops were simple enough but the relationship edits introduce some complexity:
- relationships can be one-way (e.g. class A prop 1 -> class B) or two-way (e.g. class A prop 1 <-> class B prop 2)
- if a two-way is converted to a one-way, or vice versa (i.e., when both of the classes and at least one of the properties persist) we want to transfer the old connections to the new relationship, instead of deleting entirely.
- I should also enforce the rule that a property can only target one property from a class
How to handle this? What Iām thinking:
- create a new consolidated edits array
- add the type:"transfer" relations to the array
- loop through type:"create" relations
- check if thereās an existing relation that matches both classes and one property
- if it exists:
- look for a type:"delete" which deletes this relation
- if thereās a delete, push a transfer
- if thereās not a delete, ignore this creation because itās invalid
- look for a type:"delete" which deletes this relation
- if it does not exist
- add the type:"create" normally
- if it exists:
- check if thereās an existing relation that matches both classes and one property
- loop through the type:"delete" relations
- check if thereās already a transfer for it in the consolidated array, and ignore if so
- loop through the consolidated edits array and apply the changes
1/7/2025
the current dilemma is an empty selection is showing up for
FROM
in the class retrieval SQL query, causing a syntax error. Iāve isolated the problem to be that in the sandbox file, Iām attempting to create a relation property without specifying targets, although the property implicitly has some targets, just based on the junctions Iām declaring in the sameaction_edit_class_schema
call. So there are a few dimensions here:I want to figure out why my type definitions for the input to that function arenāt flagging that there should be
relation_targets
for properties being createdI need an approach to relation props that do not have any targets. I donāt necessarily want to allow someone to create them manually, but if all the targeted classes gets deleted, I need a way of handling that which does not break things. Here is my inclination:
In the interface, warn you if your changes will result in a relation property without any targets. Allow them to do it though, because I know it would be annoying to have to go through editing every property which depends on a class before deleting the class itself.
Conditionally handle empty relation props in the class retrieval function by making them return an empty array instead of it breaking by trying select out of nonexistent SQL tables
I wonder at what stage I should be performing validation for synchronicity between the junctions and the classes being created. There have sort of been two schools of thought Iāve been bouncing between while building
action_edit_class_schema
:- goby-interface will regardless have to implement a way of on-the-fly editing the staged schema in concert with the GUI, so the input that this function will be getting programmatically should be correct.
- However, I may want to expose this function for developers to use outside of the goby-interface environment, and it should be modular and stable enough to not crash the database if you fuck something up (such as the error Iām encountering in my sandbox). Part of that is just doing type-checking to prevent malformed inputs, which would resolve my current issue, but part of it is making sure the input is logically consistent.
Right now there is a level of redundancy involved, in that Iām specifying both a list of changes to classes, which include some of the relationships which are specified by the junction list. I think in an earlier incarnation of this function, assuming I set it up correctly (which without types is a little iffy to me), it may have been able to infer the targets from the junctions. In any case thereās not an exact parity between the two arrays, such that I could inversely infer the whole junction list directly from the list of changes to classes, because it is the whole junction list: a list of every relationship that is recorded by the project database. Then thereās action_update_relations
, which is independently performing validation and figuring out what SQL changes need to be made by simply comparing the current and staged lists of junctions.
I think I wanted to pass the whole junction list because thatās way easier from the side of the interface. I will likely have the junctions separated into their own array rather than only implicitly contained in the properties, because thatās a convenient way to represent the data and because it prevents me from having to fetch the whole schema of every class. Then in the editing mode, instead of recording each edit to the relations, I would just need to record the new holistic state and give it to my code here to deal with it. But if Iām doing diffing somewhere anyway, I might as well handle that logic on the front-end, or even provide myself with some utility functions via this package to do it there.
In terms of what actually makes sense to pass to action_edit_class_schema
, I think I ought to only include the class array, and compile a list of resulting junction changes. What does this entail in terms of handling?
- For property creation: simple enough, create new junctions for each of the targets of the new property
- For class creation: no need to do anything unless a relation property is also created
- For class deletion: delete all the relations which involve this class (see discussion above of empty relations)
- For property deletion: delete any junction tables for one-way class targets of this property. For two-way property targets, instead of completely deleting the tables, I want to convert them to represent one-way class targets by the surviving property
- For property modification: if the targets change, I just need to create or delete the corresponding tables
This precipitates the realization that another thing that I will have to infer somewhere is what properties will have to be changed as a result of explicitly editing others. Namely, targets will need to be added or removed to corresponding classes based on the changes I make.
It also precipitates the realization that it will be difficult to conclude what changes I need to execute while looping over the change list, since changes may override each other (e.g. I donāt have to delete a property on a class if later on in the edit queue Iām deleting the class altogether). This is probably why I thought to pass the complete new state of the schema rather than a list of edits.
How about this - instead of consolidating the representation of the edit into one list, maybe I differentiate it more:
- List of class creations and deletions, and title/metadata edits
- List of on-property changes, like deletion/creation, data types, and title or styling
- explicitly does NOT include targets. they will be populated in 3.
- List of relation changes, like changing the targets of the properties
- does NOT include changes implied by class and property deletion. these will be inferred and added when processing #1 and #2
- DOES include uncreated properties from #2. When going through those changes
This will accomplish a few things:
- normalize the changes into different categories
- establish an order of operations which prevents changes going through that counteract/override each other
- each step depends to a certain extend on the ones that come before it. e.g. properties of a new class need the ID of the class registered before they are created, and new relationships need the IDs of newly created properties (and classes) in order to be themselves registered.
- prevent information redundancy in the parameters, and the need as a developer to explicitly detail all of the implications of the change that Iām making
- create a validation funnel for any change to the schema; since every change goes through this function, it can be the central location for any validation logic, and you can make either isolated or bulk changes, which are always handled through the same stable procedure
It has one notable drawback:
- I have to create data property columns through ALTER TABLE rather than defining them with their class. But I might have been doing this already? (yes, I am already doing this)
Another separate thing that occurs to me, which may be a way of solving the current error without philosophical ponderings, is that whatās actually causing the error is me trying to retrieve the items in a class mid-way through editing the schema, because I call refresh_class_cache
during the class/property creation process. I think this is either an oversight from when I was last working on this, or an oversight from the past couple days of converting to typescript. I should have two functions:
- One that refreshes the list of classes (with IDs, titles, metadata), and each of their schemas.
- One that refreshes the list of items for each of the classes fetched by #1, populating the items array which will be created, empty, in #1.
So in #1, the other thing I will need to do is search the cache before I replace the array to see if that class is already recorded, and copy over the items from the old ClassData
object to the new one.
Other random thoughts:
- maybe I should replace "metadata" everywhere with "attributes"
- maybe rename PropertyDefinition to PropertyConfiguration or PropertyConfig
- could I hypothetically add order to relations? just via an order column in junction tables?
- I do not think so, because the order would be different for each item
- but I could potentially add the order as an array of IDs in the property metadata? this would just require a dreaded maneuver, storing the data in multiple places...
- it could be a JSON column in junction tables keyed by class and prop... but that does sound like a Pain to manage
- could I hypothetically use one-to-many columns in the global table of junctions that identify them with properties and/or classes?
I donāt know if this would implicitly accomplish the above BUT could I just normalize the class and prop IDs in the junction list like so?:
| id INTEGER NOT NULL PRIMARY KEY | side_a_class_id INTEGER | side_a_prop_id INTEGER | side_b_class_id INTEGER | side_b_prop_id INTEGER |
FOREIGN KEY(side_a_class_id) REFERENCES system_classlist(id)
FOREIGN KEY(side_b_class_id) REFERENCES system_classlist(id)
I guess I have to decide whether to create a global properties table as well, just like objects, which could be the foreign key reference for the property ids.
- or... do I create a global table for class and prop IDs, such that I can just have side_a and side_b referencing IDs in that table, whether they are classes or properties (okay that might be slightly unhinged)
Goby technical terminology:
Some rough definitions of the terms that I use in the goby-database
codebase*.
Conceptual architecture:
item
:- an entity possessing
properties
- can either be independent
- represented as a free-floating
block
on aworkspace
canvas
- represented as a free-floating
- ...or belong to a
class
, inheriting the properties it has from saidclass
- represented as a row in a table
- an entity possessing
class
:- the declaration of a kind of
item
, with a user-defined set of properties. - represented as a table, which contains all the items belonging to a class
- the declaration of a kind of
property
:- some user-defined quality of an
item
, e.g. the title, page length, or genre of a book - two kinds:
ādataā property
: any kind of raw data, i.e. a string of text, a url, a file path, an image, a number, a data, etcetera.ārelationā property
: a kind ofconnection
drawn between items in the database.- For example, an āauthorā property of books which references items in the āauthorā class.
- It may involve
relations
to multiple different classes/+properties
- some user-defined quality of an
connection
:- a link of some kind between two
items
- a link of some kind between two
relation
:- the declaration of a kind of
connection
existing betweenitems
, mediated through their properties.- For example, in a parent-child relationship, the "parents" property in a child would be linked to the "children" property in a parent
relation
is toconnection
asclass
is toitem
- a
junction
is the technical component in SQL by whichconnections
belonging to a givenrelation
are recorded in the database
- the declaration of a kind of
Visual architecture:
workspace
:- a gridded, spatial canvas on which
items
andclasses
can be represented and edited visually as rectangular cells of mainly text content.
- a gridded, spatial canvas on which
block
:- a discrete object placed somewhere within a workspace
- typically the visual representation of an
item
orclass
(and its members)
*Unfortunately for now I canāt compose the definitions without resorting to some level of jargon, loosely pulled from my education in philosophy and logic, as well as some level of circularity, owing to the way these terms are constitued by their relation to other terms.
Things this program should be able to do:
initialization
- check if system tables exist, if not, create:
- root object (rows/cells) table that generates/records their unique ID
- junction table for individual relations
- class list
- junction table list
- image data table for all image data, referenced elsewhere by file name
- check if system tables exist, if not, create:
user actions:
- create a class
- define properties on classes
- static data
- relations
- create and/or modify the participant classes
- create and/or modify the junction table
- create objects in classes
- enter data for property
- undo anything (can this be achieved? see Implementing undo/redo below)
- sqlite has a page detailing a method for achieving this
- importing data
- csv to class
- ability to convert columns into relations by text-matching
utilities:
- create a table
- core system tables
- user-defined class tables (recording members of a class and their static properties)
- junction tables (recording defined relations between classes)
- create a table
data retrieval:
- retrieving data related to classes or objects in json form
- pagination-friendly
validation:
- changing column type
- from multiple to single
- int to string and back
- defining new relations
- making sure objects on the single-select side of a relation aren't added to multiple objects in another class
- class-to-self relations
- deleting rows, columns, and classes
- for relational properties, the related class should have the option of dropping their column, converting to a string, or (if they're connected to other existing classes) just removing those relations
- changing column type
Stored data
- class metadata:
- functional:
- properties
- type
- junction ID if relevant
- property ID
- styling: order, whether or not it displays, its column width
- properties
- styling:
- the property it uses as a label (default:name)
- its color
- functional:
Core concepts:
- relations types are a unit, embodied by a junction table
- they define a type of property, shared across its constituent classes
Junction tables (how relations work in goby)
- the targeting problem in the old system(see ref):
- when you make a relation, you can pick multiple targets. the question is: can those targets have each other as possible relations? in other words, can that junction table host relationships not involving the class on which the junction was initiated?
- the resolution:
- an overhaul of the way relations are stored and structured, so that it all around makes more sense and isn't arbitrarily tied to the shape of a big junction table (see next bullet)
- the new system:
- when you make a relation property, you pick targets like before
- you can just pick a class as a target, in which case it's one-way, or you can additionally specify a property in a targeted class to link it with
- The big change here is that properties can specify which targets they link with, rather than having to be "linked" across the board (which didn't make much sense anyway). And they can target any set of classes/link with any property as long as they follow a common sense rule:
- the basic rule governing possible relationships is that a property can only be linked to one property from a class
- however, that one property can be itself
- Q: can two properties within the same class be linked to each other?
- A: Yes. Imagine "parent of" and "child of" properties.
- Q: what happens if you start with a class_1.property_A targeting class_2 without any link, and decide to link it with class_2.property B ?
- I would transfer any unlinked relations from class_1.property_A to this new link, along with any unlinked relations from class_2.property_B which target class_1
- only caveat is I would validate the relations to make sure they don't violate any constraints on either property, e.g. class_1.property_A having a limit of 1 relation per object
- the technical implementation: individual junction tables
- rather than have a single junction table for all of the targets of a property, I'm going to have one junction table for each target. It will have just two columns, one for each class/class.property.
- following the rule above, the only condition is there can only be one junction table for a class.property and another class
- junctionlist structure:
| id | classA_id.propA_id | classA_id.propA_id | metadata? |
- each junction structure:
| classA_id.propA_id | classB_id.propB_id |`
- rather than have a single junction table for all of the targets of a property, I'm going to have one junction table for each target. It will have just two columns, one for each class/class.property.
- maybe "count" could be generalized to a "max" condition?
- although maybe in the interface still making it a toggle between the single and multi-select that people are familiar with
- this doesn't work because the conditions are supposed to determine candidates for a relation, and if this is a condition then a single select will have no candidates
Return format for relation properties:
- for each row, an array of the objects its connected to, in the format:
{class_id:X,prop_id:X,object_id:X}
Structure of SQL request including relation prop structured as JSON array
WITH cte AS (SELECT person, ('[' || GROUP_CONCAT(clothing,',') || ']') AS clothing
FROM (
SELECT person, json_object('type','shirt','id',shirts) AS clothing
FROM junction_shirts
UNION
SELECT person, json_object('type','pant','id',pants) AS clothing
FROM junction_pants
UNION
SELECT person, json_object('type','shoe','id',shoes) AS clothing
FROM junction_shoes)
GROUP BY person)
SELECT p.id, p.name, c.clothing
FROM people p LEFT JOIN cte c
ON c.person = p.id;
Window management
After some considerations about how windows will work in Goby, Iām moving forward with the idea of having the database file store information about windows in a separate table.
Here is what Iām thinking for the table structure:
window ID #
type
:home
/hopper
/ orworkspace
- Iām thinking that there will only be one
home
window and onehopper
window, added during the init process as IDs #1 and #2 in the table
- Iām thinking that there will only be one
open
:true
/false
- goby will iterate over this and check if it has to open anything
metadata
:{json}
.position
(on desktop):[x,y]
.dimensions
:[w,h]
.type
: (for workspaces)canvas
/focus
.items
:(for workspaces)[array of objects and tables in this view and their styling meta]
.position
(in window):[x,y]
- other styling TBD...
Names versus IDs:
- One goal is to make the sql database on its own somewhat legible
- However, without care, names will run amuck and renaming something will require changing the name in a thousand places.
- Current approach to this for classes and properties is have their names on the actual tables and columns, and their IDs in places where metadata for classes is stored, so at most you only need to change their name in two places
Development thoughts:
the idea is this package will be imported as a module into the application
possibly will make it a cli before i make it a gui
for class retrieval, possibly create a custom aggregate function
all user input functions begin with "action" and
Misplaced interface thoughts:
- relation-select reactivity: instead of some array-copying madness, just have the selector set to the current items as an event, fired with every data update
- editing relations:
- I think I'm going to narrow from the previous iteration of the relation creator/editor so you can only configure one relation at a time, meaning you can't edit the constraints on the other relations
- since a system-wide undo/redo could be quite difficult to implement, an alternative could be using transactions, so after making a change, particularly a table structure change, you would be prompted to commit or reject changes
- MAYBE there could even be an enterable "transaction mode", in which you make a variety of changes, and then make a decision about whether to accept or reject them.
Misplaced general organization thoughts:
- maybe the website can have a kind of "timeline" pulling in the goby are.na channels using the api, letting you drag a slider to move forward/backward in the notes i take about it, which appear as a scattered collage
Implementing undo/redo
- This isnāt top of agenda for me right now because itās really complicated, and based on my current understanding it shouldnāt be too tricky to build into the codebase later on.
- Undo/redo functionality isnāt built into SQLite, but they do detail a way of technically achieving it here. I donāt fully understand how it works yet.
- I think a simple first goal, when I do get to this, would be to implement undo/redo when it comes to simple data entry, i.e. changing table cells or adding/deleting entire rows.
- Where Iām anticipating this will get messy is when it comes to Gobyās class design, which allows you to design your own table schema. Undoing/redoing changes to table schema is a more complicated thing which probably isnāt accounted for in the customary approach linked above.
- Moreover, Iām expecting that simple changes like adding an object to a class or changing item styling will be the typical use cases for Command-Z functionality.
- For class design, I can take advantage of SQLite transactions to provide a brute force way of letting you discard all changes and roll back to a saved state. Maybe the interface can give you some way of ācommittingā changes, or a way of entering ātransaction modeā
- Another thing to consider/look into: is there a way I could integrate this with git somehow, and have a sort of brute-force undo-redo powered by rolling back changes at the raw data level? Reminds me of that thing that happens when you open an indesign file and get a second, temporary file. Could I somehow track changes while you work and live commit them?
Test suite checklist
Basic:
- create a class
- delete a class
- deal with relation fall-out
- add a row to a class
- delete a row from a class
- deal with relation fall-out
- add a data property to a class
- delete a property from a class
- not allowed if class only has one property
- deal with fallout if that class is the label
Relation properties ā test the following actions/options in relevant combinations with each other:
- adding a new relation prop
- setting the
conditions.max
(formerlycount
) and validating relations correspondingly - deleting a relation prop
- linking a relation prop to another prop, new or existing
- having a property target its own parent class
- removing a link between two props
- adding a new relation
Returning data:
- return relation props in the format specified in Return format for relation properties
Workspaces in the database
- columns in a generated workspace table:
type
(of thing, e.g. item, class, etc.)block id
(assigned for workspace purposes, should be integer primary key)concept id
(item id fortype
='item', class id fortype
='class', etc for any categories I add in the future )properties
(styling like position and size)
goby-interface/notes.md
[src]
1/20/2025
Since last touching this repo many things have changed in my tooling + my perspective:
- Iāve refactored/overhauled
goby-database
in a way that likely deprecated some of the back-end code I had set up - Svelte 5 is a thing that I want to use
- Typescript is a thing that I want to use both with svelte and electron
- Iām rethinking my interface dev priorities:
- Instead of with standalone objects, I want to begin with the class interface (as tables, cards, or something else) and more importantly with the class schema editor, which is maybe the most unique and personally interesting aspect of this.
- I donāt know if the idea of a canvas is as important to me as it was? I could totally imagine starting with a basic editor for a single class placed normally in the dom (maybe with the ability to tab between classes).
To all these ends, Iāve done a complete overhaul of the directory structure and run commands, so now I can use typescript, svelte 5 and my update to goby-database
are installed, the distribution code is more clearly bundled/isolated, and Iām giving myself a clean slate to get started with interface development again.
Connecting with what I mentioned in the last bullet, I may start by creating a new window type, 'basic', which disregards the workspace
parameters I had set out below in the anatomy section.
Anatomy of the interface:
home
: where to select a project, and detached window forindex
index
: a list of objects, classes, and workspaces in the project- accessible on the
home
page and as a drawer inworkspaces
- accessible on the
workspace
: a freeflow canvas for placing elements- object instances
- detached cells with text, images, urls, etc
- tables
- class instances
- other customized table views/class filters
- object instances
dropper
: frictionless deposit box for new items
General interface musings:
- I have an idea sketched out/in my mind for a new interface for configuring relation props, relying less on obscure language/iconography and more on physical analogies of drawing connections and wiring circuits
- Possible semantic elements
- circles for classes, diamonds for properties, squares/rectangles for objects
- Iām imagining that this iteration of the interface will be much more stylistically pared back from my previous one, in consideration of the types of interfaces Iām most comfortable working in.
- Possibly less lines
- Models/references:
- IOS Stickies
- Instead of having string versus paragraph cells, maybe I can just have a text cell with an option to wrap or not
- It would make sense / feel nice to me if sorting order isn't saved unless you explicitly save it, and if a sorting reset was easily identifiable/accessible
- In general my current thought is to implement Goby's more unconventional but conceptually important interface features, and otherwise make it as frictionless as possible, and then I can add on settings as I build which are more visually obscured but facillitate advanced usage/presentation modes
- Iām realizing the shift to the āworkspaceā model for windows clarifies a lot of things, in that by decoupling the styling from the styled class/object, I don't have to worry about things not being displayed, or being artificially constrained in their display. The data for any element is stored with minimal styling information, and then a user decides when, where, and how represent it visually, with that styling information tied to the workspace.
- An "index" drawer accessible through a button in the top-right corner of each page contains everything that exists in the database, and I'm thinking you could drag and drop stuff from it into a workspace.
- This means you could conceivable have multiple instances of an element, for example different instances of a class each filtering its contents or representing it in a visually distinct manner.
- on the development side, this means rather than looping through classes (as in the first iteration), a workspace will loop through each of the elements inside of it to place it.
- With the persistent "index" of items system, it'll have to be clear how and when an item is fully deleted versus merely stashed, and still visible. My thought right now is that items will always delete by default on using the
DEL
key, with a contextmenu (right click) option to stash them, whereas classes will be the reverse (stashed by delete key, deleted with right click)
Front-end development:
- It would be ideal to use the same UI elements for both the single select and the multiple select
- Right now I'm using a
store
value to record the currently āfocusedā UI elementās ID. But Iām anticipating in the future that there may be multiple focused items at a time, in that you may focus an element inside of the currently focused element (e.g. a search field inside of a dropdown).- To address this, I think the
store
variable will need to be an array, and the unfocus function will need to check when another element is clicked/focused to see if itās a descendant of any of the focused items in the array. If itās not, those items need to be unfocused, and if so, then the most recently interacted-with element needs to be added to the array.
- To address this, I think the
- I discovered just now with some playing around in the tutorial that if you bind an undefined variable to a component prop that has defaults, the variable will take on the default value, which is surprising and will hopefully save me some mess.
Home page
- can use recent documents list native to mac and windows to remember what projects have already been opened
- OS window customization
- opening URLs externally https://github.com/electron/electron/issues/1344#issuecomment-208839713
better-sqlite3 misadventures
better-sqlite3
is tricky to combine with electron because it uses the native node installation on your operating system, but to work with Electron it actually needs to use Electronās internal node version.
Step 1 in addressing that was re-compiling the node-module for Electronās node version, which you do by following the steps here using electron-rebuild
.
- delete
node-modules
andpackage-lock.json
- run
npm i
- run
./node_modules/.bin/electron-rebuild
However, after resolving that, I started running into an issue with Electron crashing as soon as I ran any commands with better-sqlite3
. This turned out to be brand new bug as of writing this, and to fix it the maintainers recommended running
npm install
cd node_modules/better-sqlite3
npx node-gyp rebuild --debug --build-from-source --runtime=electron --target=26.1.0 --dist-url=https://electronjs.org/headers
cd ../..
npm run start
to manually rebuild the module binary, which seems to have worked for me.
This also meant that ultimately I couldnāt just use npm link
to install the goby-database
code. But instead of just copying it over (which I did last time, ensuing in all sorts of confusions and problems), I just went ahead and published the WIP to npm, and then installed it into the goby-interface
repo.
Ways forward:
text object
- set up click event listener to add tentative text object at the clicked grid coordinate
- figure out how to wire up default item props with the
page_contents
variable - set up validator upon exiting writing mode to see whether a new item should be added to the db (if it has no id and a length>0) or if an existing item has to be deleted (if it has an id and a length<0)
- set up functions in `goby-database`` to correspondingly add/remove items and set their values
- this should be called from
item
with a debouncer so it only updates the db when it's reasonably clear you're done typing
- set up
TextCell
component usingtextarea
, with wrapping controls- set up hitting
shift
+enter
oresc
or clicking elsewhere to exit writing mode
- set up hitting
drag selection
- detect when blocks/class rows are in the selection rectangle and add them to the selection
- make the rectangle persistent if it doesn't encounter any blocks, and provide options to fill region with a text or image item
contextmenu
- set up event dispatcher signaling that an action has been clicked on in the menu
- make it appear on the left side of the mouse if the menu would go over the page edge
set up right-click "context menu" dialog with options to create a class or add an image
set up class creation, which should involve placing the circle+line and giving the class a name (which is validated to make sure itās unique)
continue considering the mechanics of different interactions, particularly the creation and modification of relation properties
*occasionally outdated/bypassed
goby feature repository
[src]
9/10/2023
Opening a multiple select field as its own isolated āblockā on the canvas
8/23/2023
Complete index:
A list of all workspaces, classes, and freestanding objects. Classes would be accordions (possibly using <summary>/<details>
), so upon clicking on them you would be able to see their constituent objects.
Iām imagining this to be accessible from the home
tab once a project is open, and possibly also as some kind of drawer nav in all workspaces.
8/23/2023
Single table workspaces/windows
Iām thinking of my fondness of the Stickies app on MacOS (where Iām currently drafting this), and the way it isolates notes in different window contexts. I think it would be nice if Goby had a similar functionality, possibly with a responsive column width (while still keeping the widths in grid square units). Iām also realizing that developers have access to the āfloat on topā window type on MacOS, so I could add that as an option.
8/23/2023
Visual joins:
In the same way that you can join tables in SQLite on a shared column, I think it would be cool if you could visually link up two or more classes using their relation properties, possibly separating multiple choice selections into multiple rows and only showing repeated information once. I could imagine how the header for a table could be augmented to represent that:
ā Typefaces + ā Foundries on ā¬©Foundry/ā¬©Created
8/20/2023
Matrix view:
Ability to create a matrix table representation of two classes intersected in their relations with a third, e.g. in a table displaying political candidate positions by issue, made using the intersection of a candidates table and issues table on a position table
goby moods
[src]
imaginary use cases
[src]
8/5/2022
meal planning
I'm envisioning a list of meals typified by cooking complexity, recipe, leftover friendliness, nutrition rating, etc., and then related to their various raw ingredients, so you could apply a filter limiting the result to what you can make with what you currently have at home. (Bonus, doubles as a running shopping list.)
8/2/2022
keeping different assets related to a project organized within a single documentation space
Right now with Goby I create a separate channel whenever I have a specific category of note which I want to write, e.g. dev notes, future features, use cases. Instead with goby, I could simply keep all these notes in one place and separate them by tables with different fields.
8/2/2022
planning a paper
The paper that Iām currently working on is giving me a moment of āgee I wish Goby was built-out enough to use for thisā, so Iām going to record the use-case so I can keep it in mind when Iām in the weeds of working on the interface later on:
I have just gotten finished reading a collection of texts by different authors. The exercise has left me feeling ready to generate a list of āthemesā which serve several purposes:
- they allow me to find patterns between the texts: different ways in which the same idea or problem is being articulated, and which I could use my paper to compare
- they allow me to group passages and quotes that I can draw upon while writing, some of which belong to multiple themes. This gives me an impetus to revisit each text as well.
- they can be related with one another, so I have a more holistic view of my topic and how different lines of argument support one another
- they can be related back to the authors, so I can get a sense of how their worldviews stand in relation to one another
This is a mapping task too complex to be done, at least in a conveniently and orderly fashion, using a simple tagging or mind-mapping tool.
Ironically the subject of the paper is in part the idea that you canāt perfectly crystallize ideas in representative logical relations, as I seem to be advocating here. But I have never seen Goby as a project of accurately representing reality; rather, the act of ordering ideas and assets in this way is a pathway, a ādisposable ladderā if you will, to greater and clearer understanding.
8/2/2022
dev log
Making Goby dev notes channel and realizing it would be useful to be able to enter bugs and future features with fields for task type, screenshots, front end v. back end, and what other entries it depends on.