dm-cutie-ui 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +0 -0
- data/LICENSE +19 -0
- data/README.markdown +61 -0
- data/Rakefile +100 -0
- data/bin/dm-cutie-ui +50 -0
- data/config.ru +10 -0
- data/lib/dm-cutie-ui.rb +107 -0
- data/lib/dm-cutie-ui/config.rb +63 -0
- data/lib/dm-cutie-ui/server.rb +222 -0
- data/lib/dm-cutie-ui/server/public/application.css +150 -0
- data/lib/dm-cutie-ui/server/public/application.js +20 -0
- data/lib/dm-cutie-ui/server/public/asc.gif +0 -0
- data/lib/dm-cutie-ui/server/public/bg.gif +0 -0
- data/lib/dm-cutie-ui/server/public/desc.gif +0 -0
- data/lib/dm-cutie-ui/server/public/jquery-dimensions.js +12 -0
- data/lib/dm-cutie-ui/server/public/jquery-tablesorter.js +2 -0
- data/lib/dm-cutie-ui/server/public/jquery-tooltip.js +19 -0
- data/lib/dm-cutie-ui/server/public/jquery.js +19 -0
- data/lib/dm-cutie-ui/server/views/cutie_models/executed_queries.erb +29 -0
- data/lib/dm-cutie-ui/server/views/cutie_models/generalized_queries.erb +38 -0
- data/lib/dm-cutie-ui/server/views/cutie_models/repository_storages.erb +21 -0
- data/lib/dm-cutie-ui/server/views/default/help.erb +1 -0
- data/lib/dm-cutie-ui/server/views/default/index.erb +7 -0
- data/lib/dm-cutie-ui/server/views/default/login.erb +32 -0
- data/lib/dm-cutie-ui/server/views/layout.erb +35 -0
- data/lib/dm-cutie-ui/server/views/shared/_grid.erb +60 -0
- data/lib/dm-cutie-ui/server/views/shared/_menu.erb +38 -0
- data/lib/dm-cutie-ui/server/views/shared/_navigation.erb +7 -0
- data/lib/dm-cutie-ui/version.rb +3 -0
- metadata +144 -0
data/History.txt
ADDED
File without changes
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2009, Cory ODaniel
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
4
|
+
copy of this software and associated documentation files (the "Software"),
|
5
|
+
to deal in the Software without restriction, including without limitation
|
6
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
7
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
8
|
+
Software is furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
16
|
+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
18
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
19
|
+
DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
Description
|
2
|
+
=============
|
3
|
+
dm-cutie-ui is a live reporting tool for dm-cutie. http://github.com/coryodaniel/dm-cutie
|
4
|
+
|
5
|
+
|
6
|
+
Adding Custom Columns
|
7
|
+
======================
|
8
|
+
The partial 'grid' takes three keys to create its local variables: :columns, :records, :adhoc_columns (discussed next)
|
9
|
+
|
10
|
+
Columns should be respond to #each, it will generally be a DataMapper PropertySet. Each element in columns will be used in a #send method call on each of the elements in records. That means instead of doing the standard
|
11
|
+
partial :grid, :locals => { :columns => MyModel.properties, :records => @my_collection}
|
12
|
+
|
13
|
+
You can add any other columns you want as long as there is a method that a 'record' will respond to. For example, every object has a 'class' method, so you could do
|
14
|
+
partial :grid,
|
15
|
+
:locals => {
|
16
|
+
:columns => MyModel.properties.to_a + [:class],
|
17
|
+
:records => @my_collection
|
18
|
+
}
|
19
|
+
|
20
|
+
This would cause the class name to be output in a column (pretty useless), but you can add any method you want to the class and simply add its name to the set of elements being passed to :columns
|
21
|
+
|
22
|
+
|
23
|
+
As an alternative method you can pass a column name to a proc in the :adhoc_columns parameter
|
24
|
+
partial :grid,
|
25
|
+
:locals => {
|
26
|
+
:columns => MyModel.properties,
|
27
|
+
:records => @my_collection,
|
28
|
+
:adhoc_columns => {
|
29
|
+
:my_cool_class_name => lambda{|my_record| my_record.class }
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
This would result in a column named 'my_cool_class_name' with a value of 'MyModel'. Obviously you can be more creative :)
|
34
|
+
|
35
|
+
Note: the proc should accept one parameter, the specific record from the collection of items passed to :records
|
36
|
+
|
37
|
+
IMPORTANT NOTE:
|
38
|
+
Remember, if you are adding additional columns to the grid, make sure you pass the column names to the 'menu' partial if you want the ability to hide that column.
|
39
|
+
|
40
|
+
|
41
|
+
DataMapper Default Context
|
42
|
+
==========================
|
43
|
+
DataMapper requires a 'default' repository. In DM UI all users use their own repository, so a fake repository is stubbed as
|
44
|
+
|
45
|
+
DataMapper.setup :default, "abstract://null"
|
46
|
+
|
47
|
+
All calls should be done through the Sinatra helper method #repo.
|
48
|
+
|
49
|
+
|
50
|
+
TODOS
|
51
|
+
=====
|
52
|
+
* If you boot a server with extras and then browse to a dm-cutie repo with out those extras you get an error
|
53
|
+
* should probably change extras loaded to a 'per repository' thing
|
54
|
+
* Make *.erbs more dry, its probably possible to get ride of them all together if the hooks had the following methods display_views, display_relationships
|
55
|
+
* Make this app less ugly, I suck horribly at CSS :)
|
56
|
+
* Deal w/ the super fields
|
57
|
+
* --include-hooks=this,that/there,etc
|
58
|
+
* figure out how to support including hooks/views that aren't a part of dm-cutie or dm-cutie-extras
|
59
|
+
* dm-pagination
|
60
|
+
* If someone built a merb-slice version of this, they would be awesome.
|
61
|
+
* Sinatra shutdown hook to clean up the tmp directory
|
data/Rakefile
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rubygems/specification'
|
4
|
+
require 'date'
|
5
|
+
require 'merb-core/version'
|
6
|
+
require 'merb-core/tasks/merb_rake_helper'
|
7
|
+
require "extlib"
|
8
|
+
|
9
|
+
require 'rake'
|
10
|
+
require 'rake/clean'
|
11
|
+
require 'spec/rake/spectask'
|
12
|
+
require "spec"
|
13
|
+
require 'rake/rdoctask'
|
14
|
+
require 'rake/gempackagetask'
|
15
|
+
|
16
|
+
ROOT = Pathname(__FILE__).dirname.expand_path
|
17
|
+
require ROOT + 'lib/dm-cutie-ui/version'
|
18
|
+
|
19
|
+
@spec = Gem::Specification.new do |s|
|
20
|
+
s.name = %q{dm-cutie-ui}
|
21
|
+
s.version = DmCutieUI::VERSION
|
22
|
+
|
23
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
24
|
+
s.authors = ["Cory ODaniel"]
|
25
|
+
s.date = %q{2009-10-15}
|
26
|
+
s.summary = s.description = %q{An interface to DM Cutie repos.}
|
27
|
+
s.email = %q{cutie@coryodaniel.com}
|
28
|
+
s.bindir = 'bin'
|
29
|
+
s.executables = ['dm-cutie-ui']
|
30
|
+
s.extra_rdoc_files = ["README.markdown", "LICENSE", "History.txt"]
|
31
|
+
s.files = ["LICENSE", "README.markdown", "Rakefile", "History.txt",
|
32
|
+
"config.ru",
|
33
|
+
"bin/dm-cutie-ui",
|
34
|
+
"lib/dm-cutie-ui.rb",
|
35
|
+
"lib/dm-cutie-ui/config.rb",
|
36
|
+
"lib/dm-cutie-ui/server.rb",
|
37
|
+
"lib/dm-cutie-ui/version.rb",
|
38
|
+
]
|
39
|
+
s.files += Dir["lib/dm-cutie-ui/server/**/*"]
|
40
|
+
s.has_rdoc = true
|
41
|
+
s.homepage = "http://github.com/coryodaniel/dm-cutie-ui"
|
42
|
+
|
43
|
+
s.add_dependency 'sinatra', '=0.9.4'
|
44
|
+
s.add_dependency 'extlib', ">=0.9.13"
|
45
|
+
s.add_dependency "dm-core", ">=0.10.1"
|
46
|
+
s.add_dependency "dm-aggregates", ">=0.10.1"
|
47
|
+
s.add_dependency "data_objects", '>=0.10.0'
|
48
|
+
s.add_dependency "dm-cutie", '>=0.3.0'
|
49
|
+
s.require_paths = ["lib"]
|
50
|
+
s.rubygems_version = %q{1.2.0}
|
51
|
+
end
|
52
|
+
|
53
|
+
[ ROOT, ROOT.parent ].each do |dir|
|
54
|
+
Pathname.glob(dir.join('tasks/**/*.rb').to_s).each { |f| require f }
|
55
|
+
end
|
56
|
+
|
57
|
+
NAME = @spec.name
|
58
|
+
GEM_VERSION = DmCutieUI::VERSION
|
59
|
+
|
60
|
+
Rake::GemPackageTask.new(@spec) do |pkg|
|
61
|
+
pkg.gem_spec = @spec
|
62
|
+
end
|
63
|
+
|
64
|
+
desc "install the plugin locally"
|
65
|
+
task :install => [:package] do
|
66
|
+
sh %{sudo gem install #{install_home} pkg/#{NAME}-#{GEM_VERSION} --no-update-sources}
|
67
|
+
end
|
68
|
+
|
69
|
+
desc "create a gemspec file"
|
70
|
+
task :make_spec do
|
71
|
+
File.open("#{NAME}.gemspec", "w") do |file|
|
72
|
+
file.puts @spec.to_ruby
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
Rake::RDocTask.new do |rdoc|
|
77
|
+
files = ["README.markdown", "History.txt", "LICENSE", "lib/**/*.rb"]
|
78
|
+
rdoc.rdoc_files.add(files)
|
79
|
+
rdoc.main = "README.markdown"
|
80
|
+
rdoc.title = "DM CutieUI"
|
81
|
+
|
82
|
+
rdoc.rdoc_dir = "doc/rdoc"
|
83
|
+
rdoc.options << "--line-numbers" << "--inline-source"
|
84
|
+
end
|
85
|
+
|
86
|
+
Spec::Rake::SpecTask.new do |t|
|
87
|
+
t.spec_files = Dir["./spec/**/*_spec.rb"]
|
88
|
+
t.spec_files.unshift './spec/spec_helper.rb'
|
89
|
+
|
90
|
+
t.libs = ['lib']
|
91
|
+
t.spec_opts << "--color" << "--format" << "specdoc" #"progress"
|
92
|
+
|
93
|
+
if ENV['RCOV']
|
94
|
+
t.rcov = true
|
95
|
+
t.rcov_opts << '--exclude' << 'pkg,spec,interactive.rb,install_test_suite.rb,lib/gems,' + Gem.path.join(',')
|
96
|
+
t.rcov_opts << '--text-summary'
|
97
|
+
t.rcov_opts << '--sort' << 'coverage' << '--sort-reverse'
|
98
|
+
t.rcov_opts << '--only-uncovered'
|
99
|
+
end
|
100
|
+
end
|
data/bin/dm-cutie-ui
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
require 'rubygems' #its poison, i know.
|
3
|
+
|
4
|
+
if `which rackup`.empty?
|
5
|
+
abort "** Can't find `rackup` in PATH."
|
6
|
+
end
|
7
|
+
|
8
|
+
if ARGV.include?('-h') || ARGV.include?('--help')
|
9
|
+
puts <<-USAGE_INFO
|
10
|
+
Usage: dm-cutie-ui [cutie-options] [ruby-options] [rack-options]
|
11
|
+
|
12
|
+
Starts the dm-cutie front end
|
13
|
+
|
14
|
+
DmCutieUI Options:
|
15
|
+
==================================================
|
16
|
+
--extras= # A comma seperated list of extras for dm-cutie to look for
|
17
|
+
(should match what you had in your app)
|
18
|
+
Examples:
|
19
|
+
dm-cutie-ui --extras=sqlite3_execution_plan
|
20
|
+
dm-cutie-ui --extras=mysql_execution_plan,mysql_warning
|
21
|
+
|
22
|
+
Rack Options:
|
23
|
+
==================================================
|
24
|
+
-s, --server SERVER serve using SERVER (webrick/mongrel)
|
25
|
+
-o, --host HOST listen on HOST (default: 0.0.0.0)
|
26
|
+
-p, --port PORT use PORT (default: 9292)
|
27
|
+
-E, --env ENVIRONMENT use ENVIRONMENT for defaults (default: development)
|
28
|
+
-D, --daemonize run daemonized in the background
|
29
|
+
-P, --pid FILE file to store PID (default: rack.pid)
|
30
|
+
|
31
|
+
USAGE_INFO
|
32
|
+
|
33
|
+
else
|
34
|
+
__DIR__ = File.expand_path( File.join(File.dirname(__FILE__), '..') )
|
35
|
+
|
36
|
+
# Simple ARGV Parser, @note include-hooks is a TODO
|
37
|
+
# Remove cutie's argv from ARGV and let Sinatra have it.
|
38
|
+
cutie_flags = [:extras, :'include-hooks']
|
39
|
+
cutie_argv = ARGV.select{|arg| arg =~ /(\-\-(#{cutie_flags.join('|')}))/}
|
40
|
+
ARGV.delete_if{|arg| cutie_argv.member?(arg)}
|
41
|
+
|
42
|
+
args = ARGV
|
43
|
+
ENV['RUBYLIB'] = ENV['RUBYLIB'].to_s + ':' + File.join(__DIR__,'lib')
|
44
|
+
args.unshift '-e', %Q{require "dm-cutie-ui"; CUTIE_ARGV=%w{#{cutie_argv.join(' ')}}}
|
45
|
+
args.push File.expand_path(
|
46
|
+
File.join(__DIR__, "config.ru")
|
47
|
+
)
|
48
|
+
|
49
|
+
exec "rackup", *args
|
50
|
+
end
|
data/config.ru
ADDED
data/lib/dm-cutie-ui.rb
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'digest/md5'
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
gem 'extlib', ">=0.9.13"
|
6
|
+
require 'extlib'
|
7
|
+
|
8
|
+
gem 'dm-cutie', '>=0.3.0'
|
9
|
+
require 'dm-cutie'
|
10
|
+
|
11
|
+
gem 'dm-aggregates', '>=0.10.1'
|
12
|
+
require 'dm-aggregates'
|
13
|
+
|
14
|
+
gem 'dm-core', '>=0.10.1'
|
15
|
+
require 'dm-core'
|
16
|
+
|
17
|
+
gem "data_objects", '>=0.10.0'
|
18
|
+
require 'data_objects'
|
19
|
+
|
20
|
+
# SEt up a faux adapter. DM requires a default repository
|
21
|
+
# Repository names are hashes of the Normalized URI and are stored in CutieUI.
|
22
|
+
DataMapper.setup :default, "abstract://null"
|
23
|
+
|
24
|
+
module DmCutieUI
|
25
|
+
class << self
|
26
|
+
def logger
|
27
|
+
@_logger ||= Logger.new(STDOUT)
|
28
|
+
end
|
29
|
+
def view_root
|
30
|
+
@_view_root ||= File.join('', 'tmp', 'dm-cutie-ui', Time.now.to_i.to_s)
|
31
|
+
end
|
32
|
+
# - routes - Routes for cutie models
|
33
|
+
#
|
34
|
+
def routes
|
35
|
+
@__routes ||={}
|
36
|
+
end
|
37
|
+
|
38
|
+
# - repos - Cache of connection strings used since boot time
|
39
|
+
#
|
40
|
+
# @return [String] connection string
|
41
|
+
def repos
|
42
|
+
@__repos ||= {}
|
43
|
+
end
|
44
|
+
|
45
|
+
# - connect - Connects to a datamapper repository
|
46
|
+
# This takes the password as an additional parameter for 'security' reasons since
|
47
|
+
# it caches all connection strings for a user
|
48
|
+
#
|
49
|
+
# @param connection [Hash]
|
50
|
+
# - string [String] connection string
|
51
|
+
# - password [String] connection password
|
52
|
+
#
|
53
|
+
# @return [String] -
|
54
|
+
#
|
55
|
+
def connect( connection )
|
56
|
+
connection_options = DataMapper::Adapters.send(:normalize_options, connection[:string])
|
57
|
+
|
58
|
+
# Cache this before adding the password if the person decided they didn't want it cached by leaving it out
|
59
|
+
normalized_uri = begin
|
60
|
+
query = connection_options.except(:adapter, :user, :password, :host, :port, :path, :fragment, :scheme, :query, :username, :database)
|
61
|
+
query = nil if query.empty?
|
62
|
+
|
63
|
+
DataObjects::URI.new(
|
64
|
+
connection_options[:adapter],
|
65
|
+
connection_options[:user] || connection_options[:username],
|
66
|
+
nil, #Dont put the password in the cache
|
67
|
+
connection_options[:host],
|
68
|
+
connection_options[:port],
|
69
|
+
connection_options[:path] || connection_options[:database],
|
70
|
+
query,
|
71
|
+
connection_options[:fragment]
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Create a hash of the normalized_uri
|
76
|
+
token = Digest::MD5.hexdigest(normalized_uri.to_s).to_sym
|
77
|
+
|
78
|
+
# Cache the uri
|
79
|
+
DmCutieUI.repos[token] = normalized_uri.to_s
|
80
|
+
|
81
|
+
# Add the password if it was provided
|
82
|
+
connection_options[:password] = connection[:password] unless connection[:password].blank?
|
83
|
+
|
84
|
+
adapter = DataMapper::Adapters.new token, connection_options
|
85
|
+
|
86
|
+
DataMapper::Repository.adapters[adapter.name] = adapter
|
87
|
+
|
88
|
+
if DataMapper::Cutie.valid_repo? adapter.name
|
89
|
+
return token
|
90
|
+
else
|
91
|
+
return false
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def root
|
96
|
+
@_root_path ||= File.expand_path(File.dirname(__FILE__)) / 'dm-cutie-ui'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
require DmCutieUI.root / :version
|
102
|
+
|
103
|
+
class String
|
104
|
+
def truncate(len,repl='...')
|
105
|
+
(self.length <= (len - repl.length)) ? self : self.slice(0,len) + repl.to_s
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
puts CUTIE_ARGV
|
3
|
+
|
4
|
+
cutie_ui_config = CUTIE_ARGV.inject({}) do |conf, arg|
|
5
|
+
config_key, config_vals = arg.split('=')
|
6
|
+
|
7
|
+
if config_key
|
8
|
+
# { :extras => ['mysql', 'sqlite3'] }
|
9
|
+
config_value = config_vals.blank? ? true : config_vals.split(',')
|
10
|
+
|
11
|
+
conf[config_key.gsub('--','').to_sym] = config_value
|
12
|
+
conf
|
13
|
+
else
|
14
|
+
conf
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
# dm-cutie-ui has a bunch of views, but views may also come from dm-cutie-extras and eventually add'l plugins
|
20
|
+
# since we need a path to all the views, we create a temp folder and copy the views their
|
21
|
+
# as well as any other views from additional gems/reqs
|
22
|
+
|
23
|
+
# Configure DmCutieUI
|
24
|
+
FileUtils.mkdir_p DmCutieUI.view_root
|
25
|
+
FileUtils.cp_r(
|
26
|
+
File.join(DmCutieUI.root, "server", "views"), DmCutieUI.view_root
|
27
|
+
)
|
28
|
+
DmCutieUI.logger.info "View temp directory: #{DmCutieUI.view_root}"
|
29
|
+
|
30
|
+
|
31
|
+
# If extras were requested, get them.
|
32
|
+
if cutie_ui_config[:extras]
|
33
|
+
begin
|
34
|
+
require 'dm-cutie-extras'
|
35
|
+
rescue LoadError => ex
|
36
|
+
DmCutieUI.logger.error "dm-cutie-extras were requested, but the gem was not found: gem install dm-cutie-extras"
|
37
|
+
exit(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
cutie_ui_config[:extras].each do |extra|
|
41
|
+
begin
|
42
|
+
# Load the extra
|
43
|
+
DataMapper::Cutie::Extras.load extra.to_sym
|
44
|
+
|
45
|
+
# move the hook's view into the DmCutieUI.view_root/cutie_models directory
|
46
|
+
#/tmp/dm-cutie-ui/view/1258150564/views/cutie_models/#{extra}.erb
|
47
|
+
# render a extras views by doing
|
48
|
+
# render :'cutie_models/#{extra}'
|
49
|
+
|
50
|
+
FileUtils.cp DataMapper::Cutie::Extras.view_path[extra.to_sym], DmCutieUI.view_root / 'views' / 'cutie_models'
|
51
|
+
rescue LoadError => ex
|
52
|
+
DmCutieUI.logger.error "dm-cutie-extra '#{extra}' does not exist."
|
53
|
+
exit(2)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Thanks to dkubb: this make sure that the PropertySet always contains remote keys
|
59
|
+
descendants = DataMapper::Model.descendants.to_a
|
60
|
+
while model = descendants.shift
|
61
|
+
descendants.concat(model.descendants.to_a - [ model ])
|
62
|
+
model.send(:assert_valid)
|
63
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module DmCutieUI
|
5
|
+
class Server < Sinatra::Base
|
6
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
7
|
+
set :sessions, true
|
8
|
+
set :static, true
|
9
|
+
set :public, dir / "server" / "public"
|
10
|
+
set :views, DmCutieUI.view_root / 'views'
|
11
|
+
|
12
|
+
# BEGIN ROUTES
|
13
|
+
get('/help') { erb :'default/help' }
|
14
|
+
|
15
|
+
get '/' do
|
16
|
+
session["history"].each do |repo_key|
|
17
|
+
# Remove the key from the cookie, it was from a previous server boot
|
18
|
+
session["history"].delete(repo_key) if DmCutieUI.repos[repo_key].blank?
|
19
|
+
end if session["history"]
|
20
|
+
|
21
|
+
session.delete('current') if params['disconnect']
|
22
|
+
|
23
|
+
if !DmCutieUI.repos[session["current"]].blank?
|
24
|
+
erb :'default/index'
|
25
|
+
else
|
26
|
+
erb :'default/login'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
post '/' do
|
31
|
+
begin
|
32
|
+
# This will be used by the repo method to get access to the repo the user selected
|
33
|
+
repo_key = DmCutieUI.connect params[:connection]
|
34
|
+
|
35
|
+
if repo_key
|
36
|
+
session["history"] ||= []
|
37
|
+
|
38
|
+
session["history"] << repo_key unless session["history"].member?(repo_key)
|
39
|
+
session["current"] = repo_key.to_sym
|
40
|
+
erb :'default/index'
|
41
|
+
else
|
42
|
+
@connection_error = "That repository is missing some dm-cutie storages (#{DataMapper::Cutie.missing_storage.join(', ')})"
|
43
|
+
erb :'default/login'
|
44
|
+
end
|
45
|
+
rescue Exception => ex
|
46
|
+
# DataObjects::SyntaxError, LoadError
|
47
|
+
@connection_error = ex.message
|
48
|
+
erb :'default/login'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
###################### GENERATE ROUTES ####################
|
54
|
+
# Generate routes for all files in 'sinatra/views/cutie_models'
|
55
|
+
# TODO: Create routes for --include-hooks once its supported
|
56
|
+
DataMapper::Cutie::MODELS.each do |model|
|
57
|
+
view_name = model.to_s.pluralize
|
58
|
+
view_path = DmCutieUI.view_root / 'views' / 'cutie_models' / "#{view_name}.erb"
|
59
|
+
view_uri = "/#{view_name}"
|
60
|
+
if File.exist? view_path
|
61
|
+
DmCutieUI.routes[view_uri] = {
|
62
|
+
:model => model,
|
63
|
+
:file => view_path,
|
64
|
+
:view_name => view_name
|
65
|
+
}
|
66
|
+
|
67
|
+
# Create the 'controller'
|
68
|
+
get view_uri do
|
69
|
+
if !DmCutieUI.repos[session["current"]].blank?
|
70
|
+
# The cutie model being viewed
|
71
|
+
|
72
|
+
@view_name = DmCutieUI.routes[ request.path_info ][:view_name]
|
73
|
+
@cutie_model = DataMapper::Cutie.get_klass DmCutieUI.routes[ request.path_info ][:model]
|
74
|
+
|
75
|
+
@title = DmCutieUI.routes[ request.path_info ][:model]
|
76
|
+
|
77
|
+
# Keep the response scoped to the users selected Cutie Repo
|
78
|
+
user_current_repo { erb(:"cutie_models/#{@view_name}") }
|
79
|
+
else
|
80
|
+
@connection_error = "Select a DM repository to connect to"
|
81
|
+
redirect '/'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
elsif !@model.blank?
|
86
|
+
puts "A view was not found for: #{@model}. This is probably an anonymous resource."
|
87
|
+
end # else probably an anonymous resource
|
88
|
+
end
|
89
|
+
|
90
|
+
# END ROUTES
|
91
|
+
|
92
|
+
# BEGIN HELPERS
|
93
|
+
helpers do
|
94
|
+
include Rack::Utils
|
95
|
+
alias_method :h, :escape_html
|
96
|
+
|
97
|
+
################
|
98
|
+
# DM Cutie UI doesn't need your applications models
|
99
|
+
# she knows what she needs to know about them through
|
100
|
+
# what DM Cutie stored in her tables
|
101
|
+
# TODO - Remove the need for uniq by grouping these, also consider a smart way to cache them per user
|
102
|
+
################
|
103
|
+
|
104
|
+
# Gets a list of repo names from the Cutie Repo
|
105
|
+
def repository_names
|
106
|
+
user_current_repo do
|
107
|
+
RepositoryStorage.all().map{ |rs| rs.repo_name }.uniq
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Gets a list of model names from the Cutie Repo
|
112
|
+
def model_names
|
113
|
+
user_current_repo do
|
114
|
+
RepositoryStorage.all().map{ |rs| rs.model_name }.uniq
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
# Gets a list of adapter names from the Cutie Repo
|
119
|
+
def adapter_names
|
120
|
+
user_current_repo do
|
121
|
+
RepositoryStorage.all().map{ |rs| rs.adapter_name }.uniq
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Get the users chosen repository context
|
126
|
+
def user_current_repo
|
127
|
+
repository( session["current"] ) { yield }
|
128
|
+
end
|
129
|
+
|
130
|
+
def partial(template, *args)
|
131
|
+
template = File.join('shared',"_#{template}").to_sym
|
132
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
133
|
+
options.merge!(:layout => false)
|
134
|
+
|
135
|
+
|
136
|
+
if collection = options.delete(:collection) then
|
137
|
+
collection.inject([]) do |buffer, member|
|
138
|
+
buffer << erb(template, options.merge(
|
139
|
+
:layout => false,
|
140
|
+
:locals => {template.to_sym => member}
|
141
|
+
)
|
142
|
+
)
|
143
|
+
end.join("\n")
|
144
|
+
else
|
145
|
+
erb(template, options)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Parses the params hash looking for params that are properties of the model
|
150
|
+
#
|
151
|
+
def parse_params(model)
|
152
|
+
params.only *model.properties.map{|p| p.name.to_s} # Have to string this since sinatra params isnt a mash
|
153
|
+
end
|
154
|
+
|
155
|
+
def link_to(text,href)
|
156
|
+
%Q{<a href="#{href}">#{text}</a>}
|
157
|
+
end
|
158
|
+
|
159
|
+
# ram_filters - Filters for repository, adapter, and model
|
160
|
+
#
|
161
|
+
# An access for params[*_filter]
|
162
|
+
# Should be passed to determine the records to pass to display (Default provided: _grid partial)
|
163
|
+
def ram_filters
|
164
|
+
{
|
165
|
+
:repository => params['repository_filter'],
|
166
|
+
:adapter => params['adapter_filter'],
|
167
|
+
:model => params['model_filter']
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
171
|
+
# This is just a helper to get the property name or return the symbol if multiple data types are passed to
|
172
|
+
# the 'grid' partials :columns attribute
|
173
|
+
#
|
174
|
+
# @param col [DataMapper::Property|Symbol]
|
175
|
+
# @returns [Symbol]
|
176
|
+
#
|
177
|
+
def column_name(col)
|
178
|
+
if col.is_a?(Symbol)
|
179
|
+
return col
|
180
|
+
else
|
181
|
+
return col.name.to_sym
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Adds a help link to the top of the page
|
186
|
+
def help_link
|
187
|
+
@help_link = %q{<a href="#help" class="help_link">help</a>}
|
188
|
+
end
|
189
|
+
|
190
|
+
# Creates a hyperlink to a filtered related model
|
191
|
+
#
|
192
|
+
def relationship_link(relationship, record)
|
193
|
+
relationship_name = relationship.name
|
194
|
+
|
195
|
+
# This isnt going to work if multipart keys are ever used because its just doing parent_key.first
|
196
|
+
if relationship.parent_model == @cutie_model
|
197
|
+
filter_value = record.send relationship.parent_key.first.name
|
198
|
+
remote_model_key = relationship.child_key.first.name
|
199
|
+
remote_model = relationship.child_model
|
200
|
+
else #its the child model
|
201
|
+
filter_value = record.send relationship.child_key.first.name
|
202
|
+
remote_model_key = relationship.parent_key.first.name
|
203
|
+
remote_model = relationship.parent_model
|
204
|
+
end
|
205
|
+
|
206
|
+
remote_model_name = DataMapper::Cutie.get_human_name(remote_model).to_s.pluralize
|
207
|
+
total_remote_records = remote_model.all( remote_model_key => filter_value ).count
|
208
|
+
link_to "View: #{total_remote_records}", "/#{remote_model_name}?#{remote_model_key}=#{filter_value}"
|
209
|
+
end
|
210
|
+
|
211
|
+
# Returns 'selected="selected"' to reselect filter drop downs
|
212
|
+
def apply_selected_attribute(filter_name, filter_value)
|
213
|
+
if ram_filters[filter_name] == filter_value
|
214
|
+
'selected="SELECTED"'
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# END HELPERS
|
220
|
+
|
221
|
+
end
|
222
|
+
end
|