dm-cutie-ui 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|