Permalink
Browse files

Allow sorting of mocks.

  • Loading branch information...
1 parent 4f85f1f commit 0244b410c52f16f489cf3b6c518a5c8817660bab @iridakos committed Apr 10, 2016
@@ -1 +1,4 @@
-$(function(){ $(document).foundation(); });
+$(function(){
+ $(document).foundation();
+ $('.sortable').sortable();
+});
@@ -1,21 +1,71 @@
-var first_error_tab = null;
+setMockPositions = function () {
+ $('div.mock').each(function(i) {
+ $(this).data('new-pos', i);
+ });
+}
-$(function(){
- $('form.mock-form').find('.tabs-content .content').each(function(index, element) {
- var $element = $(element);
- var elementId = $element.prop('id');
- var $tabLink = $('a[href="#' + elementId + '"]');
+updateMocksOrder = function (event) {
+ event.preventDefault();
+
+ setMockPositions();
- if ($element.find('small.error').length) {
- $tabLink.addClass('error');
+ var $sortable = $('.sortable');
- if (!first_error_tab) {
- first_error_tab = $tabLink;
- }
+ var updates = [];
+
+ $('div.mock').each(function(i) {
+ var $element = $(this),
+ old_pos = $element.data('old-pos'),
+ new_pos = $element.data('new-pos');
+
+ console.log(old_pos, new_pos);
+
+ if (old_pos != new_pos) {
+ updates.push({id: $element.data('mock-id'), order: new_pos});
}
});
- if (first_error_tab) {
- first_error_tab.trigger('click');
+ var success_url = $sortable.data('mock-success-url');
+
+ if (updates.length > 0) {
+ var url = $sortable.data('mock-url'),
+ method = $sortable.data('mock-method');
+
+ $.ajax({
+ type: method,
+ url: url,
+ data: { order: updates },
+ success: function () {
+ document.location = success_url;
+ }
+ });
+ } else {
+ document.location = success_url;
}
+}
+
+$(function(){
+ if ($('form.mock-form').find('.tabs-content .content').length > 0) {
+ var first_error_tab = null;
+
+ $('form.mock-form').find('.tabs-content .content').each(function(index, element) {
+ var $element = $(element);
+ var elementId = $element.prop('id');
+ var $tabLink = $('a[href="#' + elementId + '"]');
+
+ if ($element.find('small.error').length) {
+ $tabLink.addClass('error');
+
+ if (!first_error_tab) {
+ first_error_tab = $tabLink;
+ }
+ }
+ });
+
+ if (first_error_tab) {
+ first_error_tab.trigger('click');
+ }
+ }
+
+ $('.update-mocks-order').on('click', updateMocksOrder);
});
@@ -30,3 +30,39 @@ table {
}
}
}
+
+div.mock {
+ clear: both;
+
+ border: 1px solid #666;
+ background-color: #f9f9f9;
+ margin-bottom: 10px;
+ padding: 10px;
+ min-height: 50px;
+ cursor: move;
+
+ &:after {
+ content: " ";
+ display: block;
+ height: 0;
+ clear: both;
+ }
+
+ .mock-name {
+ font-size: 20px;
+ font-weight: bold;
+ color: #444;
+ }
+}
+
+.sortable-placeholder {
+ border: 1px dashed #CCC;
+ background-color: #f9f9f9;
+ min-height: 50px;
+ margin-bottom: 10px;
+}
+
+.sortable {
+ display: list-item;
+ list-style: none;
+}
@@ -4,12 +4,17 @@
module Duckrails
class MocksController < ApplicationController
before_action :load_mock, only: [:edit, :update, :destroy, :deactivate, :activate]
- after_action :reload_routes, only: [:update, :create, :destroy, :deactivate, :activate]
+ after_action :reload_routes, only: [:update, :create, :destroy, :deactivate, :activate, :update_order]
skip_before_action :verify_authenticity_token, :only => [:serve_mock]
def index
- @mocks = Duckrails::Mock.page params[:page]
+ if params[:sort]
+ @mocks = Duckrails::Mock.all
+ render :sort_index
+ else
+ @mocks = Duckrails::Mock.page params[:page]
+ end
end
def edit
@@ -30,6 +35,17 @@ def update
end
end
+ def update_order
+ Duckrails::Mock.transaction do
+ params[:order].values.each do |mock_order|
+ mock = Duckrails::Mock.find(mock_order[:id])
+ mock.update_attribute(:mock_order, mock_order[:order])
+ end
+ end
+
+ render nothing: true
+ end
+
def create
@mock = Duckrails::Mock.new mock_params
@@ -9,7 +9,7 @@ class Duckrails::Mock < ActiveRecord::Base
validates :status, presence: true
validates :request_method, presence: true
validates :content_type, presence: true
- validates :route_path, presence: true, route: true, uniqueness: { scope: :request_method }
+ validates :route_path, presence: true, route: true
validates :name, presence: true, uniqueness: { case_sensitive: false }
validates :body_type, inclusion: { in: [SCRIPT_TYPE_STATIC,
SCRIPT_TYPE_EMBEDDED_RUBY,
@@ -25,9 +25,12 @@ class Duckrails::Mock < ActiveRecord::Base
validates :script, presence: { unless: 'script_type.blank?' }
validates :active, presence: { if: 'active.nil?' }
+ before_save :set_order
after_save :register
after_destroy :unregister
+ default_scope { order(mock_order: :asc) }
+
def dynamic?
body_type != SCRIPT_TYPE_STATIC
end
@@ -44,6 +47,10 @@ def deactivate!
protected
#########
+ def set_order
+ self.mock_order ||= (Duckrails::Mock.maximum(:mock_order) || 0) + 1
+ end
+
def register
Duckrails::Router.register_mock self
end
@@ -84,6 +84,11 @@
<div class="page-actions">
<div class="row">
<div class="small-12 columns">
+ <%= link_to duckrails_mocks_path(sort: true), class: 'button secondary' do %>
+ <i class="fa fa-bars"></i>
+ <span><%= t :change_mocks_order %></span>
+ <% end if @mocks.size > 1 %>
+
<%= link_to new_duckrails_mock_path, class: 'button' do %>
<i class="fa fa-plus"></i>
<span><%= t :create_new_mock %></span>
@@ -0,0 +1,29 @@
+<%= content_tag :div,
+ class: 'sortable',
+ data: {
+ mock_url: update_order_duckrails_mocks_path,
+ mock_method: :put,
+ mock_success_url: duckrails_mocks_path
+ } do %>
+ <% @mocks.each do |mock| %>
+ <%= content_tag :div, data: { mock_id: mock.id, old_pos: mock.mock_order }, class: 'mock' do %>
+ <div class="left mock-name">
+ <%= mock.name %>
+ </div>
+
+ <div class="right mock-path">
+ <%= mock.route_path %>
+ </div>
+
+ <div class="right mock-request-method">
+ <%= mock.request_method %>
+ </div>
+ <% end %>
+ <% end %>
+<% end %>
+
+<div class="page-actions">
+ <%= link_to t(:cancel), duckrails_mocks_path, class: 'button secondary' %>
+
+ <%= link_to t(:save), '#', class: 'button success update-mocks-order' %>
+</div>
@@ -22,7 +22,7 @@
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
- config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present?
+ config.serve_static_files = true
# Compress JavaScripts and CSS.
config.assets.js_compressor = :uglifier
View
@@ -9,6 +9,10 @@
put :activate
put :deactivate
end
+
+ collection do
+ put :update_order
+ end
end
end
View
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160410092607) do
+ActiveRecord::Schema.define(version: 20160410174605) do
create_table "headers", force: :cascade do |t|
t.string "name", limit: 255, null: false
@@ -37,10 +37,10 @@
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "active", default: true, null: false
+ t.integer "mock_order", limit: 4, null: false
end
add_index "mocks", ["name"], name: "index_mocks_on_name", unique: true, using: :btree
- add_index "mocks", ["request_method", "route_path"], name: "index_mocks_on_request_method_and_route_path", unique: true, using: :btree
add_foreign_key "headers", "mocks", on_delete: :cascade
end
View
@@ -13,24 +13,30 @@ def register_mock(mock)
def register_current_mocks
REGISTERED_MOCKS << Duckrails::Mock.pluck(:id)
REGISTERED_MOCKS.flatten!
+ REGISTERED_MOCKS.uniq!
end
def unregister_mock(mock)
REGISTERED_MOCKS.delete mock.id
end
def load_mock_routes!
- REGISTERED_MOCKS.each do |mock_id|
- define_route mock_id
+ mocks = REGISTERED_MOCKS.map do |mock_id|
+ Duckrails::Mock.find mock_id
+ end
+
+ mocks = mocks.sort_by{ |mock| mock.mock_order }
+
+ mocks.each do |mock|
+ define_route mock
end
end
protected
- def define_route(mock_id)
- mock = Duckrails::Mock.find mock_id
-
+ def define_route(mock)
return unless mock.active?
+
Duckrails::Application.routes.draw do
self.send(:match, mock.route_path, to: 'duckrails/mocks#serve_mock', defaults: { duckrails_mock_id: mock.id }, via: mock.request_method)
end
View
@@ -9,7 +9,7 @@ def validate_each(record, attribute, value)
route = Rails.application.routes.recognize_path(value, method: record.request_method)
# If the route exists, then it should belong to the same record in order to be valid
# or else we would allow many mocks to have the same route
- valid = route[:controller] == 'duckrails/mocks' && route[:action] == 'serve_mock' && route[:duckrails_mock_id] == record.id
+ valid = route[:controller] == 'duckrails/mocks' && route[:action] == 'serve_mock'
rescue URI::InvalidURIError => exception
# Bad URI
record.errors[attribute] << (options[:message] || 'is not a valid route')
Oops, something went wrong.

0 comments on commit 0244b41

Please sign in to comment.