Summary
There is no way to read a phase's fields from Terraform, which makes this the most useful missing data source of the set. Field ids are input to almost everything else: automation search_for and trigger_field_ids, field conditions (#45), pipe relation own_field_maps, and AI agent fields_attributes. Today a config that references any of those has to hardcode ids copied out of the UI.
Part of #89.
What the API allows
resource_field.go:197 reads through the phase and matches on id client-side:
query GetPhaseFields_tf($phaseId:ID!){ phase(id:$phaseId){ fields{ ... } } }
There is no singular field(id:) in use, so a lookup needs the phase. The useful shape is a list keyed on phase_id, not a single field by id.
Proposed
pipefy_phase_fields, taking phase_id and returning the phase's fields with fieldgql.Selection: id, internal_id, uuid, label, type, required, options, description, help, editable, minimal_view, custom_validation, index.
index is a GraphQL Float and is modeled as types.Float64 in the resource (resource_field.go:48). Keep that in the data source; it is not an Int.
Start form fields need no separate data source. The start form is a phase, and pipegql.Selection already exposes startFormPhaseId, so pipefy_pipe gives the phase id that this data source then takes.
Worth deciding: whether to also expose a map keyed by label, so a config can write data.pipefy_phase_fields.x.by_label["Client email"].id instead of filtering a list in HCL. Labels are not unique within a phase, so a map would have to either collide or key on something else.
Notes
Overlaps the third item in #49, which proposes the same thing as part of a discovery bundle. Build it once and close the other item.
The client has no pagination. A phase with many fields may need cursor handling.
Follow #88 for how this talks to the API.
Conventions this issue settles
This is the first data source of the eight, so its PR sets the pattern for the rest. Decide these here rather than per issue, and note the outcome in the PR description:
Naming. Singular for the entities the API can fetch by id (automation(id:), table(id:), aiAgent(uuid:)), plural named after the parent for the ones that can only be listed through it (pipefy_phase_fields, pipefy_pipe_labels, pipefy_pipe_webhooks, pipefy_table_fields, pipefy_pipe_relations). That is what #91 through #97 assume. Changing it means changing all of them.
Shared selection. pipegql and the other *gql packages exist so a resource and its data source read the same fields and cannot drift. Reuse the existing package rather than duplicating the selection string, and follow #88 for how the read reaches the API.
Sensitive values. A data source has no equivalent of a write-only attribute: everything it returns is readable in plan output and in state. Three of the eight touch values that may be secrets (webhook url in #94, agent action field values in #97, automation action_params in #95, which is currently not read at all). Settle whether the default is to omit those or to mark them Sensitive.
Attribute coverage. Beyond the sensitive cases, a data source should not silently omit fields users will want to reference. Where the resource has an attribute, the default is to expose it. Where the API does not read one back at all, say so in the documentation rather than leaving it out quietly (webhook headers is the known case, see #94).
Summary
There is no way to read a phase's fields from Terraform, which makes this the most useful missing data source of the set. Field ids are input to almost everything else: automation
search_forandtrigger_field_ids, field conditions (#45), pipe relationown_field_maps, and AI agentfields_attributes. Today a config that references any of those has to hardcode ids copied out of the UI.Part of #89.
What the API allows
resource_field.go:197reads through the phase and matches on id client-side:There is no singular
field(id:)in use, so a lookup needs the phase. The useful shape is a list keyed onphase_id, not a single field by id.Proposed
pipefy_phase_fields, takingphase_idand returning the phase's fields withfieldgql.Selection:id,internal_id,uuid,label,type,required,options,description,help,editable,minimal_view,custom_validation,index.indexis a GraphQL Float and is modeled astypes.Float64in the resource (resource_field.go:48). Keep that in the data source; it is not an Int.Start form fields need no separate data source. The start form is a phase, and
pipegql.Selectionalready exposesstartFormPhaseId, sopipefy_pipegives the phase id that this data source then takes.Worth deciding: whether to also expose a map keyed by label, so a config can write
data.pipefy_phase_fields.x.by_label["Client email"].idinstead of filtering a list in HCL. Labels are not unique within a phase, so a map would have to either collide or key on something else.Notes
Overlaps the third item in #49, which proposes the same thing as part of a discovery bundle. Build it once and close the other item.
The client has no pagination. A phase with many fields may need cursor handling.
Follow #88 for how this talks to the API.
Conventions this issue settles
This is the first data source of the eight, so its PR sets the pattern for the rest. Decide these here rather than per issue, and note the outcome in the PR description:
Naming. Singular for the entities the API can fetch by id (
automation(id:),table(id:),aiAgent(uuid:)), plural named after the parent for the ones that can only be listed through it (pipefy_phase_fields,pipefy_pipe_labels,pipefy_pipe_webhooks,pipefy_table_fields,pipefy_pipe_relations). That is what #91 through #97 assume. Changing it means changing all of them.Shared selection.
pipegqland the other*gqlpackages exist so a resource and its data source read the same fields and cannot drift. Reuse the existing package rather than duplicating the selection string, and follow #88 for how the read reaches the API.Sensitive values. A data source has no equivalent of a write-only attribute: everything it returns is readable in plan output and in state. Three of the eight touch values that may be secrets (webhook
urlin #94, agent action field values in #97, automationaction_paramsin #95, which is currently not read at all). Settle whether the default is to omit those or to mark themSensitive.Attribute coverage. Beyond the sensitive cases, a data source should not silently omit fields users will want to reference. Where the resource has an attribute, the default is to expose it. Where the API does not read one back at all, say so in the documentation rather than leaving it out quietly (webhook
headersis the known case, see #94).