Add custom field support to plnk-core and plnk - #3
Merged
Conversation
Add BaseCustomFieldGroup, CustomFieldGroup, CustomField and CustomFieldValue to plnk-core, with UpdateCustomFieldGroup / UpdateCustomField param structs and Tabular impls for all four. Extend BoardSnapshotIncluded, CardSnapshotIncluded and ProjectSnapshotIncluded with the custom field collections, and add CustomFieldGroupSnapshot plus ProjectsListSnapshot envelopes. Models carry no consumer yet, so the new envelope fields are marked dead_code until the API traits land. Unit tests deserialize payloads captured verbatim from a live server, including the adopted-group case where name is null and the display name lives on the base group.
Add CustomFieldGroupApi, CustomFieldApi and CardCustomFieldApi, implement all
three for PlankaClientV1, and export them from plnk_core::api.
Base custom field groups are a distinct wire resource with their own routes, so
they get their own methods rather than being folded into the group methods.
There is no GET /api/base-custom-field-groups/{id} route at all, so base groups
are read from the projects list; PATCH and DELETE on that prefix do exist and
are used directly.
list_fields and find_fields take a base flag because a base group's fields are
reachable only through the projects list. list_fields_for_card reads the card
snapshot so name resolution can fetch a card's own fields in one call.
clear_field_value maps a 404 to Ok(()) — clearing means 'ensure unset', which an
already-unset field satisfies. Only that route's 404 is swallowed.
12 wire tests pin the composite value path with no dollar sign, the plural
DELETE route, idempotent clear, base-vs-group create routing, and explicit
false surviving a field PATCH.
Add the field-group resource to the clap tree, wired to CustomFieldGroupApi, with the hidden field-groups plural alias. --project, --board and --card form one mutually exclusive scope group on list, find and create. A project scope yields base groups and a board or card scope yields ordinary groups; these are different types with different columns and are not forced through one shape. get, update and delete try the ordinary route first and fall back to the base route on a not-found, because base groups are a separate wire resource and an ID alone does not say which kind it is. Falling back on delete is safe: the first request made no change. Add baseCustomFieldGroupId to CustomFieldGroup's trimmed columns. An adopted group's own name is null, so without it the trimmed row is a blank name with nothing explaining why.
Add the field resource to the clap tree, wired to CustomFieldApi, with the hidden fields plural alias. --group and --base-group form one mutually exclusive scope group on list, find and create. The pair resolves to a group ID plus a base flag, because the kind cannot be inferred from an opaque ID and the two are reached by different routes. --show-on-front is a bare flag on create, defaulting to false to match Planka. On update it takes an explicit true or false so that leaving it unset stays distinguishable from setting it false in the PATCH body.
Add the value surface under card, mirroring card label, with ID-or-name resolution for --group and --field. Resolution reaches through the base group. A card group adopted from a base group has name: null and carries no fields of its own, so both the group name and the field names must be looked up on the base group. Matching a card group by its own name alone would match nothing for every template-adopted group, which is the common case. The base-group lookup is skipped entirely when no group needs it, and costs one request rather than one per group. Arguments that are already IDs skip resolution completely. Values are validated before any request is issued: empty is rejected with a message naming card field clear, and over-length is rejected against the 512 character cap. Both would otherwise cost a round trip and return an opaque 400. Add list_all_base_field_groups to CustomFieldGroupApi — resolving a card's adopted groups needs their names without walking card to board to project. 12 e2e tests against the mock server. Removing the base-group fallback fails six of them, including both resolution tests; the ID-bypass test still passes, which is the correct split.
Add docs/cli/custom-fields.md, linked from the README and from the grammar reference, plus a worked example in docs/cli/examples.md covering the full template-to-value round trip. Record the verified wire quirks in AGENTS.md. Several contradict Planka's published OpenAPI spec, including three that cost a debugging round trip to find: there is no GET route for base custom field groups (it returns the SPA's HTML with 200), base group fields are absent from the board snapshot, and an adopted card group carries neither a name nor any fields of its own. Add machine-help examples for all three resources and tests asserting that the help text states what --show-on-front controls, the 512 character cap, and that clearing is a separate command. Extend the alias tests to cover field-groups and fields, and the resource sweep to cover field-group and field. CHANGELOG entry under Unreleased.
The skill is symlinked into ~/.claude/skills, so agents load it directly from this repo — without these entries an agent has no way to know the commands exist. Its frontmatter description drives discovery, so the custom field keywords go there too. references/commands.md gains field-group, field and card field sections plus intent-table and alias entries. references/api-quirks.md gains the three traps an agent will actually hit: an adopted group has no name and no fields of its own, base groups are only partly routed, and the value rules around the 512 character cap, empty values and idempotent clear. docs/cli/cards.md gains a card field section next to card label, since card field is a card subcommand and readers look for it there. The Jekyll site under docs/ enumerates no resources, so nothing there is stale; its What's new card is a release-time change and the feature is still unreleased.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds custom field support across the SDK and CLI: three new resources (
field-group,field,card field) with full CRUD, ID-or-name resolution following the house three-tier match, and client-side validation of Planka's 512-character cap.Name resolution reaches through base groups — a card group adopted from a template has a null name and no fields of its own, so both the group name and its field names resolve via
baseCustomFieldGroupId. Every endpoint was verified against a live Planka server, and the wire quirks found along the way (several contradicting Planka's published OpenAPI spec, including a base-group GET route that returns HTML with a 200) are recorded in AGENTS.md.