Skip to content
GitLab
Projects Groups Snippets
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • A administrate
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
  • Issues 96
    • Issues 96
    • List
    • Boards
    • Service Desk
    • Milestones
  • Merge requests 32
    • Merge requests 32
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • thoughtbot, inc.
  • administrate
  • Issues
  • #2291
Closed
Open
Issue created Nov 25, 2022 by Alfonso Mancilla@ammancilla

Multiple "looks" per Field

What would you like to be able to do? Can you provide some examples?

As a developer I can define multiple looks for a Field and determine which one to use when using the field.

For example, I have a dashboard with three Field::HasMany attributes. For one of them I want to use the "default look" (the set of partials provided by administrate) but for the other two I want to use two different "looks" defined by me.


How could we go about implementing that?

Introduce the concept of looks (or variants?). A look is a group of partials that determine how a Field is displayed in different pages. There is a default look provided by administrate (the existing partials for each field) and developers can create, within their applications, as many custom looks as needed.

app/
├─ views/
│  ├─ fields/
│  │  ├─ belongs_to/
│  │  │  ├─ looks/
│  │  │  │  ├─ default/
│  │  │  │  │  ├─ _form.html.erb
│  │  │  │  │  ├─ _show.html.erb
│  │  │  │  │  ├─ _index.html.erb
│  │  ├─ has_many/
│  │  │  ├─ looks/
│  │  │  │  ├─ default/

...

Creating custom looks

A custom look is created by adding a new folder (named after the look) under app/views/fields/<field_name>/looks/ with the respective partials to render a Field. A custom look might define all or a subset of the three partials needed for a Field. In case of missing partials, the ones defined in the default look are used as fallback.

app/
├─ views/
│  ├─ fields/
│  │  ├─ belongs_to/
│  │  │  ├─ looks/
│  │  │  │  ├─ simple/
│  │  │  │  │  ├─ _index.html.erb
│  │  │  │  ├─ extended/
│  │  │  │  │  ├─ _show.html.erb

Using a custom look

To use a custom look, its name is passed as an option to a Field. If the option is not given, the default look is used.

  # app/dashboards/book_dashboard.rb

  ATTRIBUTE_TYPES = {
    pages: Field::HasMany,
    authors: Field::HasMany.with_options(look: :simple),
    publishers: Field::HasMany.with_options(look: :extended)
  }
  # administrate/lib/administrate/field/base.rb

  def to_partial_path
    look = options.fetch(:look, :default)
    partial_path = partial_path(page, look)
    
    if look != :default && lookup_context.exists?(partial_path, [], true)
     partial_path
    else
     partial_path(page, :default)
    end
  end

  private

  def partial_path(page, look)
    "/fields/#{self.class.field_type}/#{look}/#{page}"
  end

Can you think of other approaches to the problem?

An alternative, in my opinion less structured approach, would be to allow developers to specify the individual custom partials to be used to render a Field, through a new option (partials or so). If no custom partials are given then the default ones are used.

  • Dashboard
  # app/dashboards/book_dashboard.rb

  ATTRIBUTE_TYPES = {
    pages: Field::HasMany,
    authors: Field::HasMany.with_options(partials: { index: '/path/to/custom/partial'}),
    publishers: Field::HasMany.with_options(partials: { show: '/path/to/custom/partial'})
  }
  • Aministrate Base field
# administrate/lib/administrate/field/base.rb

def to_partial_path
  options.dig(:partials, page) || "/fields/#{self.class.field_type}/#{page}"
end

The strategy I've been using so far.

So far, whenever I need an extra "look" for a Field I create a new Field (without custom behaviour), that inherits from the respective administrate Field. Then, use the custom field in the dashboard for the attributes that need the custom look.

For example:

def HasManyExtendedView < Field::HasMany; end

def HasManySimpleView < Field::HashMany; end
  # app/dashboards/book_dashboard.rb

  ATTRIBUTE_TYPES = {
    pages: Field::HasMany,
    authors: HasManySimpleView,
    publishers: HasManyExtendedView
  }

This approach doesn't scale and results in having a lot of unnecessary files/code (a bunch of custom fields without custom behaviour)

Assignee
Assign to
Time tracking