Class: PlanMyStuff::Project

Inherits:
ApplicationRecord show all
Defined in:
lib/plan_my_stuff/project.rb

Overview

Wraps a GitHub Projects V2 project with its statuses, items, and fields. Class methods provide the public API for CRUD and query operations.

Follows an ActiveRecord-style pattern:

  • ‘Project.find` / `Project.list` return persisted instances

  • ‘ProjectItem.add_item` / `ProjectItem.add_draft_item` for adding items

  • ‘ProjectItem.move_item` / `ProjectItem.assign` for item mutations

Constant Summary collapse

MAX_AUTO_PAGINATE_ITEMS =
500
ITEMS_PER_PAGE =
100

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationRecord

#new_record?, #persisted?

Constructor Details

#initialize(**attrs) ⇒ Project

Returns a new instance of Project.

See Also:

  • super


410
411
412
413
414
415
416
417
418
# File 'lib/plan_my_stuff/project.rb', line 410

def initialize(**attrs)
  @id = attrs.delete(:id)
  @number = attrs.delete(:number)
  @closed = attrs.delete(:closed)
  super
  @statuses ||= []
  @fields ||= []
  @items ||= []
end

Instance Attribute Details

#closedBoolean (readonly)

Returns whether the project is closed.

Returns:

  • (Boolean)

    whether the project is closed



20
21
22
# File 'lib/plan_my_stuff/project.rb', line 20

def closed
  @closed
end

#fieldsArray<Hash>

Returns all field definitions.

Returns:

  • (Array<Hash>)

    all field definitions



29
30
31
# File 'lib/plan_my_stuff/project.rb', line 29

def fields
  @fields
end

#has_next_pageBoolean?

Returns whether more pages exist (only in cursor mode).

Returns:

  • (Boolean, nil)

    whether more pages exist (only in cursor mode)



35
36
37
# File 'lib/plan_my_stuff/project.rb', line 35

def has_next_page
  @has_next_page
end

#idString (readonly)

Returns GitHub node ID.

Returns:

  • (String)

    GitHub node ID



16
17
18
# File 'lib/plan_my_stuff/project.rb', line 16

def id
  @id
end

#itemsArray<PlanMyStuff::ProjectItem>

Returns project items.

Returns:



31
32
33
# File 'lib/plan_my_stuff/project.rb', line 31

def items
  @items
end

#next_cursorString?

Returns cursor for next page (only in cursor mode).

Returns:

  • (String, nil)

    cursor for next page (only in cursor mode)



33
34
35
# File 'lib/plan_my_stuff/project.rb', line 33

def next_cursor
  @next_cursor
end

#numberInteger (readonly)

Returns project number.

Returns:

  • (Integer)

    project number



18
19
20
# File 'lib/plan_my_stuff/project.rb', line 18

def number
  @number
end

#statusesArray<Hash>

Returns status options (name:).

Returns:

  • (Array<Hash>)

    status options (name:)



27
28
29
# File 'lib/plan_my_stuff/project.rb', line 27

def statuses
  @statuses
end

#titleString

Returns project title.

Returns:

  • (String)

    project title



23
24
25
# File 'lib/plan_my_stuff/project.rb', line 23

def title
  @title
end

#urlString

Returns project URL.

Returns:

  • (String)

    project URL



25
26
27
# File 'lib/plan_my_stuff/project.rb', line 25

def url
  @url
end

Class Method Details

.create(title:) ⇒ Object

Creates a new project in the configured organization.

Parameters:

  • title (String)

Returns:

  • (Object)

Raises:

  • (NotImplementedError)


44
45
46
# File 'lib/plan_my_stuff/project.rb', line 44

def create(title:)
  raise(NotImplementedError, "#{name}.create is not yet implemented")
end

.find(number, paginate: :auto, cursor: nil) ⇒ PlanMyStuff::Project

Finds a project by number with its statuses, items, and fields.

Parameters:

  • number (Integer)
  • paginate (Symbol) (defaults to: :auto)

    :auto (default) or :cursor

  • cursor (String, nil) (defaults to: nil)

    pagination cursor for :cursor mode (from a previous call’s next_cursor)

Returns:



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/plan_my_stuff/project.rb', line 80

def find(number, paginate: :auto, cursor: nil)
  org = PlanMyStuff.configuration.organization

  case paginate
  when :auto
    find_auto_paginated(org, number)
  when :cursor
    find_with_cursor(org, number, cursor: cursor)
  else
    raise(ArgumentError, "Unknown paginate mode: #{paginate.inspect}. Use :auto or :cursor")
  end
end

.listArray<PlanMyStuff::Project>

Lists all projects in the configured organization.

Returns:



63
64
65
66
67
68
69
70
# File 'lib/plan_my_stuff/project.rb', line 63

def list
  org = PlanMyStuff.configuration.organization
  data = PlanMyStuff.client.graphql(list_query, variables: { org: org })

  nodes = data.dig(:organization, :projectsV2, :nodes) || []

  nodes.map { |node| build_summary(node) }
end

.update(project_number:, title: nil) ⇒ Object

Updates an existing project.

Parameters:

  • project_number (Integer)
  • title (String, nil) (defaults to: nil)

Returns:

  • (Object)

Raises:

  • (NotImplementedError)


55
56
57
# File 'lib/plan_my_stuff/project.rb', line 55

def update(project_number:, title: nil)
  raise(NotImplementedError, "#{name}.update is not yet implemented")
end

Instance Method Details

#status_fieldHash

Returns the Status single-select field definition.

Returns:

  • (Hash)

    with :id and :options keys

Raises:



426
427
428
429
430
431
432
# File 'lib/plan_my_stuff/project.rb', line 426

def status_field
  field = fields.find { |f| f[:name] == 'Status' && f[:options] }

  raise(APIError, "No 'Status' field found on project ##{number}") unless field

  field
end