Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flex components #612

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,8 @@ gem "puma", "~> 5.0"

gem "fog-aws"
gem 'ddtrace', require: 'ddtrace/auto_instrument'

# The dummy app can behave more like our typical apps
gem 'graphql'
gem 'graphiql-rails'
gem 'settingslogic'
9 changes: 9 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ GEM
bundler
rake
thor (>= 0.14.0)
base64 (0.2.0)
bcrypt (3.1.16)
better_errors (2.9.1)
coderay (>= 1.0.0)
Expand Down Expand Up @@ -208,6 +209,10 @@ GEM
formatador (1.1.0)
globalid (1.0.0)
activesupport (>= 5.0)
graphiql-rails (1.10.0)
railties
graphql (2.3.4)
base64
guard (2.18.0)
formatador (>= 0.2.4)
listen (>= 2.7, < 4.0)
Expand Down Expand Up @@ -405,6 +410,7 @@ GEM
childprocess (>= 0.5, < 5.0)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2)
settingslogic (2.0.9)
shellany (0.0.1)
shoulda-matchers (5.1.0)
activesupport (>= 5.2.0)
Expand Down Expand Up @@ -469,6 +475,8 @@ DEPENDENCIES
factory_bot_rails (~> 4.8.2)
fae-rails!
fog-aws
graphiql-rails
graphql
guard-rspec
mysql2
pg
Expand All @@ -482,6 +490,7 @@ DEPENDENCIES
ruby-prof
sass
selenium-webdriver
settingslogic
shoulda-matchers
thin
webrick
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ https://www.faecms.com/documentation
* [Disabling Environments](docs/features/disable_envs.md)
* [Form Field Label & Helper Text Manager](docs/features/form_manager.md)
* [Netlify Deploy Monitor](docs/features/netlify.md)
* [Flex Components](docs/features/flex_components.md)


### Tutorials
Expand Down
6 changes: 6 additions & 0 deletions app/assets/javascripts/fae/form/_ajax.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,12 @@ Fae.form.ajax = {
if ($el.find('.js-content-header').length) {
Fae.navigation.stickyHeaders(true);
}

// This is so flex components will open their forms after the initial
// selection of component type then save happens.
if ($el.find('table').data('initialCreate')) {
$el.find('.js-edit-link').last().trigger('click');
}
}

// if there's a form wrap, slide it up before replacing content
Expand Down
17 changes: 17 additions & 0 deletions app/controllers/fae/flex_component_base_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Fae
class FlexComponentBaseController < Fae::NestedBaseController

def update
if @item.update(permitted_params)
@parent_item = @item.flex_component.flex_componentable

flash[:notice] = t('fae.save_notice')
render template: 'fae/shared/_flex_components_table', formats: :html, locals: { assoc: :flex_components, parent_item: @parent_item }
else
build_assets
render action: 'edit'
end
end

end
end
53 changes: 53 additions & 0 deletions app/controllers/fae/flex_components_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
module Fae
class FlexComponentsController < Fae::NestedBaseController

def new
@item = @klass.new
@item.flex_componentable_id = params[:item_id]
@item.flex_componentable_type = params[:item_class]
build_assets
end

def create
@item = @klass.new(permitted_params)

if @item.save
component = @item.component_model.constantize.new
component.save(validate: false)
@item.update(component_id: component.id)

@parent_item = @item.flex_componentable
flash[:notice] = t('fae.save_notice')
render partial: 'fae/shared/flex_components_table', locals: {assoc: :flex_components, parent_item: @parent_item, initial_create: true}
else
build_assets
render action: 'new'
end
end

def destroy
@parent_item = @item.flex_componentable

if @item.destroy
flash[:notice] = t('fae.delete_notice')
else
flash[:alert] = t('fae.delete_error')
end
render partial: 'fae/shared/flex_components_table', locals: {assoc: :flex_components, parent_item: @parent_item}
end

private

def set_class_variables
@klass_name = 'Fae::FlexComponent'
@klass = @klass_name.classify.constantize
@klass_singular = @klass_name.singularize
end

# only allow trusted parameters, override to white-list
def permitted_params
params.require('flex_component').permit!
end

end
end
23 changes: 23 additions & 0 deletions app/models/concerns/fae/base_flex_component_concern.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Fae
module BaseFlexComponentConcern
extend ActiveSupport::Concern

def parent_object
flex_component.flex_componentable
end

def component_type_name
self.class.name.titleize
end

module ClassMethods

def has_flex_component(model_name)
has_one :flex_component, -> { where('fae_flex_components.component_model' => model_name) },
foreign_key: 'component_id', class_name: 'Fae::FlexComponent'
end

end

end
end
1 change: 1 addition & 0 deletions app/models/concerns/fae/flex_component_concern.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module Fae::FlexComponentConcern; end
28 changes: 28 additions & 0 deletions app/models/fae/flex_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Fae
class FlexComponent < ApplicationRecord
include Fae::BaseModelConcern
include Fae::FlexComponentConcern

before_destroy :destroy_associated_component

acts_as_list add_new_at: :bottom, scope: [:flex_componentable_type, :flex_componentable_id]
default_scope { order(:position) }

belongs_to :flex_componentable, polymorphic: true

validates :component_model, presence: true

def component_instance
component_model.classify.constantize.find_by_id(component_id)
end

def component_model_human
component_instance.component_type_name.gsub('Component','')
end

def destroy_associated_component
component_instance.destroy
end

end
end
22 changes: 22 additions & 0 deletions app/views/fae/flex_components/_form.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
ruby:
form_options = {
html: {
multipart: true,
novalidate: true,
class: 'js-file-form',
remote: true,
data: {
type: "html",
form_manager_model: @item.fae_form_manager_model_name,
form_manager_info: (@form_manager.present? ? @form_manager.to_json : nil)
}
},
url: fae.flex_components_path
}
= simple_form_for([:admin, @item], form_options) do |f|
= fae_input f, :component_model, collection: Fae::FlexComponent.components_for(@item.flex_componentable_type)
= f.hidden_field :flex_componentable_type
= f.hidden_field :flex_componentable_id

= f.submit
= button_tag 'Cancel', type: 'button', class: 'js-cancel-nested cancel-nested-button'
3 changes: 3 additions & 0 deletions app/views/fae/flex_components/edit.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.nested-form
h2 Edit Flex Component
== render 'form'
3 changes: 3 additions & 0 deletions app/views/fae/flex_components/new.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.nested-form
h2 New Flex Component
== render 'form'
56 changes: 56 additions & 0 deletions app/views/fae/shared/_flex_components_table.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
ruby:
require_locals(['assoc', 'parent_item'], local_assigns)

# optional locals
assoc_name ||= assoc.to_s # 'restaurant_bars'
title ||= assoc_name.titleize # 'Restaurant Bars'

# Need to specifiy that the item_class is a StaticPage if the parent_item is a StaticPage
# or the flex_componentable_type field gets set wrong.
item_class = parent_item.class.name
item_class = 'Fae::StaticPage' if parent_item.class.ancestors.include?(Fae::StaticPage)
new_path = fae.new_flex_component_path(item_class: item_class, item_id: parent_item.id)

# See _ajax.js for usage
initial_create ||= false
helper_text ||= nil

section.addedit-form.js-addedit-form
a.js-add-link.table-add-link.button.-small href=new_path New Component
h2 = title
- if helper_text.present?
h6.table-helper-text = helper_text
== render 'fae/application/flash_messages'

table.js-sort-row data-initial-create="#{initial_create}"
thead
tr
th.th-sortable-handle
th Component Type
th Preview
th Image
th On Stage
th On Prod
th.-action
tbody
- records = parent_item.send(assoc)
- if records.present?
- records.each do |item|
tr id=tr_id(item)
td.sortable-handle: i.icon-sort
td: a.js-edit-link href=main_app.send("edit_#{fae_path}_#{item.component_model.underscore}_path", item.component_id) = item.component_model_human
td = item.fae_display_field
td
- if item.preview_image_url.present?
img src=item.preview_image_url
td = fae_toggle item, :on_stage
td = fae_toggle item, :on_prod
td = fae_delete_button item, "/#{fae_path}/#{assoc_name}/#{item.id.to_s}", class: 'js-tooltip table-action js-delete-link', remote: true

- else
tr
- td_link = link_to 'add some', new_path, class: 'js-add-link'

td colspan=4 No components yet, #{td_link}.

.js-addedit-form-wrapper
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
end
resources :users
resources :deploy_hooks
resources :flex_components

get 'settings' => 'users#settings', as: 'settings'
get 'deploy' => 'deploy#index', as: 'deploy'
Expand Down
14 changes: 14 additions & 0 deletions db/migrate/20240531185556_create_fae_flex_components.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
class CreateFaeFlexComponents < ActiveRecord::Migration[7.0]
def change
create_table :fae_flex_components do |t|
t.references :flex_componentable, polymorphic: true, null: false
t.string :component_model, index: true
t.integer :component_id, index: true
t.integer :position, index: true
t.boolean :on_stage, index: true, default: true
t.boolean :on_prod, index: true, default: false

t.timestamps
end
end
end
Loading