Skip to content

Commit

Permalink
added visualisation config
Browse files Browse the repository at this point in the history
  • Loading branch information
kpvarma committed Jan 24, 2025
1 parent 47397ee commit fd11af7
Show file tree
Hide file tree
Showing 9 changed files with 398 additions and 35 deletions.
11 changes: 6 additions & 5 deletions app/controllers/crudify/api/v1/metadata_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,26 @@ class MetadataController < ApplicationController

# Index action - Render specific metadata of all models
def index

# Get the models for which devise auth is configured
unless defined?(Devise) && Devise.respond_to?(:mappings) && Devise.mappings.any?
devise_models = []
else
devise_models = Devise.mappings.map{|x, y| y.class_name}
devise_models = Devise.mappings.map { |_x, y| y.class_name }
end

# Generate the models metadata
models_metadata = CRUDify.configuration.crudify_models.map do |model_name, config|
{
name: model_name,
menu: config.get_menu,
title: config.get_title,
description: config.get_description,
is_devise_model: devise_models.include?(model_name)
is_devise_model: devise_models.include?(model_name),
visual_config: CRUDify.configuration.crudify_visuals[model_name]&.to_h
}
end


# Render the response as JSON
render json: models_metadata, status: :ok
end

Expand Down
103 changes: 103 additions & 0 deletions app/controllers/crudify/api/v1/visualisations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
module CRUDify
module Api
module V1
class VisualisationsController < ApplicationController

before_action :authenticate_token
before_action :set_model_metadata

def catch_all_collection_action
action_name = params[:action_name].to_sym

# Fetch model configuration
config = CRUDify.configuration.crudify_visuals[@model_name]

unless config
render json: { error: "Visualisation for the Model #{@model_name} is not configured in CRUDify" }, status: :not_found
return
end

# Check if the action exists in custom collection actions
action = config.collection_end_points.find { |a| a[:name] == action_name }

unless action
render json: { error: "End Point #{action_name} is not defined for #{@model_name} Visualisation" }, status: :unprocessable_entity
return
end

# Dynamically execute the action logic
instance_exec(&action[:logic])
end

def catch_all_member_action
action_name = params[:action_name].to_sym

# Fetch model configuration
config = CRUDify.configuration.crudify_visuals[@model_name]

unless config
render json: { error: "Visualisation for the Model #{@model_name} is not configured in CRUDify" }, status: :not_found
return
end

# Check if the action exists in custom member actions
action = config.entity_end_points.find { |a| a[:action_name] == action_name }

unless action
render json: { error: "End Point #{action_name} is not defined for #{@model_name} Visualisation" }, status: :unprocessable_entity
return
end

# Dynamically execute the action logic
instance_exec(&action[:logic])
end

private

def set_model_metadata
@model_name = params[:model_name] # Extract model_name from URL
unless @model_name
render json: { error: "Crudify not configured for the model: #{params[:model_name]}" }, status: :unprocessable_entity
return
end

@model_config = CRUDify.configuration.crudify_models[@model_name]
unless @model_config
render json: { error: "Crudify not configured for the model: #{params[:model_name]}" }, status: :unprocessable_entity
return
end

@model_class = @model_name.classify.constantize
end

def resource_params
params.require(@model_class.name.underscore.to_sym).permit!
end

def scoped_collection
# Get list columns and associations to include
@list_columns = @model_config.get_list_columns
@association_includes = @list_columns.map { |col| col[:options][:include] }.compact

unless @list_columns
render json: { error: "Crudify not configured for the model: #{@model_class.name}" }, status: :unprocessable_entity
return
end

# Fetch pagination parameters
@page = params[:page].to_i > 0 ? params[:page].to_i : 1
@per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : @model_config.get_records_per_page.first

# Calculate offset
@offset = (@page - 1) * @per_page

# Fetch records with associations and apply pagination
relation = @model_class.all
relation = relation.includes(*@association_includes) if @association_includes.any?
relation = relation.offset(@offset).limit(@per_page)
end

end
end
end
end
33 changes: 7 additions & 26 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,32 +26,13 @@
put '/:id/:action_name', to: 'dynamic_crud#catch_all_member_action', as: 'catch_all_member_action'
end

# CRUDify.configuration.crudify_models.each do |model_name, config|
# endpoints = Array(config.get_api_end_points || [])
# custom_member_actions = Array(config.get_custom_member_actions.map { |action| action[:action_name] } || [])
# custom_collection_actions = Array(config.get_custom_collection_actions.map { |action| action[:action_name] } || [])

# # Rails.logger.tagged("CRUDify") do
# # Rails.logger.error "routes.rb endpoints: #{endpoints}"
# # Rails.logger.error "routes.rb custom_member_actions: #{custom_member_actions}"
# # Rails.logger.error "routes.rb custom_collection_actions: #{custom_collection_actions}"

# # Register standard RESTful routes with `only`
# resources model_name.to_s.underscore.pluralize, only: endpoints do
# # Add custom GET actions dynamically for individual resources
# custom_member_actions.each do |action|
# # Rails.logger.error "routes.rb action: #{action}"
# get action, on: :member # For member-level actions (applies to specific resource)
# end

# custom_collection_actions.each do |action|
# Rails.logger.error "routes.rb action: #{action}"
# get action, on: :collection # For collection actions (applies to specific resource)
# end
# end
# # end

# end
scope '/visualisations/:model_name' do
# Route for dynamic collection actions for collection visualisations
get '/:action_name', to: 'visualisations#catch_all_collection_action', as: 'catch_all_collection_visualisation'

# Route for dynamic member actions for entity visualisations
get '/:id/:action_name', to: 'visualisations#catch_all_member_action', as: 'catch_all_member_visualisation'
end

end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/crudify/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class << self
attr_accessor :configuration

# Delegate register methods to the configuration
delegate :register, :register_user, to: :configuration
delegate :register, :visualise, to: :configuration
end

def self.configure
Expand Down
25 changes: 24 additions & 1 deletion lib/crudify/configuration/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,20 @@
require_relative "column_config"
require_relative "form_config"

require_relative "model_visual_config"
require_relative "metric_config"
require_relative "visualisation_config"

module CRUDify
module Configuration
class Base
attr_accessor :crudify_models, :default_api_end_points, :admin_namespace, :exclude_models
attr_accessor :crudify_models, :crudify_visuals, :default_api_end_points, :admin_namespace, :exclude_models

def initialize
@default_api_end_points = [:index, :create, :read, :update, :delete]
@admin_namespace = "crudify_admin"
@crudify_models = {} # Initialize an empty dict for configurable models
@crudify_visuals = {} # Initialize an empty dict for configurable models
@exclude_models = [] # Models to exclude from auto-registration
end

Expand All @@ -33,6 +38,24 @@ def register(model_name, &block)
# Store the configuration in the dictionary using the class name as the key
@crudify_models[model_class_name] = model_config
end

# Register visualisation with a model
def visualise(model_name, &block)
# Ensure `model_name` is always a string representing the class name
model_class_name = model_name.is_a?(String) ? model_name : model_name.name

# Skip registration if the model is excluded
return if exclude_models.include?(model_class_name)

# Initialize a new ModelVisualConfig with the class name
model_visual_config = ModelVisualConfig.new(model_class_name)

# Evaluate the block to configure the model if provided
model_visual_config.instance_eval(&block) if block_given?

# Store the configuration in the dictionary using the class name as the key
@crudify_visuals[model_class_name] = model_visual_config
end

end
end
Expand Down
63 changes: 63 additions & 0 deletions lib/crudify/configuration/metric_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@

module CRUDify
module Configuration
class MetricConfig
attr_reader :name

def initialize(name, options = {})
@name = name
@visualisation = options[:visualisation]
@title = options[:title] || name.to_s.titleize
@caption = options[:caption] || "Caption for #{name}"
@data = options[:data]
@highlights = options[:highlights] || []
end

# Getter and setter for visualisation
def visualisation(value = nil)
return @visualisation if value.nil?
@visualisation = value
end

# Getter and setter for title
def title(value = nil)
return @title if value.nil?
@title = value
end

# Getter and setter for caption
def caption(value = nil)
return @caption if value.nil?
@caption = value
end

# Getter and setter for data
def data(value = nil)
return @data if value.nil?
@data = value
end


# Add highlight configuration for a metric
def highlight(title:, caption: nil, value:)
@highlights << { title: title, caption: caption, value: value }
end

def highlights
@highlights
end

def to_h
{
name: name,
visualisation: visualisation,
title: title,
caption: caption,
data: data,
highlights: highlights
}
end
end
end
end

Loading

0 comments on commit fd11af7

Please sign in to comment.