Class: Ecoportal::API::GraphQL::Base::Template::ChangeLogEntry

Inherits:
Logic::BaseModel show all
Defined in:
lib/ecoportal/api/graphql/base/template/change_log_entry.rb

Overview

One entry of a TEMPLATE's change log — a single command the platform recorded against the template. Read-only.

── Where it comes from (verified in the Rails backend on 2026-08-19) ──────────── app/graphql/types/pages/template_type.rb declares field :commands, Types::Pages::Interfaces::WorkflowCommandInterface.connection_type and resolves it as NewEp::Pages::Workflows::Commands::Base.where(page: object.page) .from_template_builder.order(_id: :desc)

The narrow Template type itself is reachable as template { ... } on any page, because app/graphql/types/pages/interfaces/base_page_interface.rb:27 declares field :template, Types::Pages::TemplateType, null: true

── ★ TWO ACCESS CAVEATS — both are silent, neither raises ─────────────────────

  1. commands returns nil, not an empty connection, unless the caller satisfies Pages::TemplatePolicy#update_information? (return unless allowed_to?(...)). A read-only account therefore sees NO change log and gets no error saying so. Treat a nil connection as "not permitted", never as "nothing changed".
  2. The scope is .from_template_builder — only TEMPLATE_BUILDER-sourced commands appear. WORKFLOW_BUILDER commands against the same page are EXCLUDED (app/models/new_ep/pages/workflows/commands/base.rb, enum_field :feature_source with values WORKFLOW_BUILDER / TEMPLATE_BUILDER). For the workflow-builder side of the same log see Query::PagesWorkflowCommands. Ordering is _id: :desc — newest first, server-side, not configurable.

── ★ WHY THIS LOG BEATS POLLING A WATERMARK ────────────────────────────────── app/services/new_ep/pages/run_merged_forces.rb:17 writes with @page.timeless.skip_patch_incr.rewrite(only_if: { updated_at: @page.updated_at.utc }) so a forces run bumps NEITHER patchVer NOR updatedAt. Any change tracker that polls a watermark is structurally blind to force-driven change; the command log is per-change and cannot be skipped that way. (OPEN: whether forces run against TEMPLATES specifically is NOT confirmed — do not assume either way.)

── Field set ───────────────────────────────────────────────────────────────── These are the fields of the INTERFACE PagesWorkflowCommandInterface only (app/graphql/types/pages/interfaces/workflow_command_interface.rb). The concrete implementing types add their own (PagesWorkflowCommandChange.changes, PagesWorkflowCommandChangeMessage.changeMessages, PagesWorkflowCommandEsChange.changes); __typename is passed through so a caller can branch, and those extras can be selected with an inline fragment or by reusing Fragment :PagesWorkflowCommandFields.

Enum-valued fields are exposed as plain strings:

  • commandAction: WorkflowCommandActionEnum

Direct Known Subclasses

Model::Template::ChangeLogEntry

Constant Summary collapse

DETAIL_KINDS =

Which of the three concrete command types this entry is, as a symbol: :changes | :change_messages | :es_changes | nil (unknown/unselected __typename). Use it instead of string-matching __typename at call sites.

{
  'PagesWorkflowCommandChange'        => :changes,
  'PagesWorkflowCommandChangeMessage' => :change_messages,
  'PagesWorkflowCommandEsChange'      => :es_changes
}.freeze

Constants included from Common::GraphQL::Model::Diffable

Common::GraphQL::Model::Diffable::DIFF_CLASS

Instance Method Summary collapse

Methods included from Concerns::SnakeCamelAccess

#method_missing, #respond_to_missing?

Methods included from Common::GraphQL::Model::AsInput

#as_input, included

Methods included from Common::GraphQL::Model::Diffable

#as_update, #dirty?

Methods included from Common::GraphQL::ClassHelpers

included

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Ecoportal::API::GraphQL::Concerns::SnakeCamelAccess

Instance Method Details

#changes ⇒ Object

── What actually changed (only populated by the DETAIL selection) ────────── Present only when the node was selected with Fragment :TemplateChangeLogEntryDetail (see Query::TemplateChangeLog.detail_block / api.template.change_log(detail: true)). With the default light selection both readers are empty — empty means "not selected", NOT "nothing changed", exactly like the nil-connection caveat above.

Deliberately raw hashes rather than a typed embed: the two changes-bearing types do not share a shape (ChangeType.from/to are Strings; StoredEsFilterChangeType.from/to are objects), so one typed model would have to lie about one of them. This mirrors Base::PagesWorkflow::CommandChange#changes, which does the same for the workflow-builder side of the same interface.



87
88
89
# File 'lib/ecoportal/api/graphql/base/template/change_log_entry.rb', line 87

def changes
  Array(doc['changes'])
end

#detail? ⇒ Boolean

True when this entry carries field-level detail. False both when the light selection was used and when a command genuinely recorded no changes -- those two are indistinguishable from the response alone, which is why the caller should know which selection it asked for.



110
111
112
# File 'lib/ecoportal/api/graphql/base/template/change_log_entry.rb', line 110

def detail?
  !changes.empty? || !changeMessages.to_a.empty?
end

#detail_kind ⇒ Object



102
103
104
# File 'lib/ecoportal/api/graphql/base/template/change_log_entry.rb', line 102

def detail_kind
  DETAIL_KINDS[__typename]
end