ssh-hull 1.0.0
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.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +44 -0
- data/.gitignore +27 -0
- data/.rubocop.yml +62 -0
- data/.tool-versions +1 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +142 -0
- data/LICENSE +19 -0
- data/README.md +12 -0
- data/Rakefile +7 -0
- data/bin/bundle +114 -0
- data/bin/rake +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bomb +12 -0
- data/config/locales/en.yml +71 -0
- data/config/locales/fr.yml +71 -0
- data/exe/ssh-hull +12 -0
- data/exe/ssh-tunnel +1 -0
- data/lib/ssh-hull/cli.rb +113 -0
- data/lib/ssh-hull/logger.rb +6 -0
- data/lib/ssh-hull/ui/application.rb +47 -0
- data/lib/ssh-hull/ui/forms/application_form.rb +69 -0
- data/lib/ssh-hull/ui/forms/host_form.rb +27 -0
- data/lib/ssh-hull/ui/forms/tunnel_form.rb +31 -0
- data/lib/ssh-hull/ui/helpers/application_window_helper.rb +233 -0
- data/lib/ssh-hull/ui/helpers/common/form_helper.rb +169 -0
- data/lib/ssh-hull/ui/helpers/common/minimize_helper.rb +46 -0
- data/lib/ssh-hull/ui/helpers/common/modal_helper.rb +43 -0
- data/lib/ssh-hull/ui/helpers/common/toolbar_helper.rb +106 -0
- data/lib/ssh-hull/ui/helpers/common/translation_helper.rb +18 -0
- data/lib/ssh-hull/ui/helpers/common/tree_view_helper.rb +40 -0
- data/lib/ssh-hull/ui/helpers/host_window_helper.rb +230 -0
- data/lib/ssh-hull/ui/helpers/tunnel_window_helper.rb +96 -0
- data/lib/ssh-hull/ui/models/config.rb +82 -0
- data/lib/ssh-hull/ui/models/host.rb +90 -0
- data/lib/ssh-hull/ui/models/tunnel.rb +118 -0
- data/lib/ssh-hull/ui/status_icon.rb +45 -0
- data/lib/ssh-hull/ui/windows/about_window.rb +32 -0
- data/lib/ssh-hull/ui/windows/application_window.rb +42 -0
- data/lib/ssh-hull/ui/windows/hosts/delete_window.rb +56 -0
- data/lib/ssh-hull/ui/windows/hosts/edit_window.rb +39 -0
- data/lib/ssh-hull/ui/windows/hosts/new_window.rb +45 -0
- data/lib/ssh-hull/ui/windows/tunnels/delete_window.rb +57 -0
- data/lib/ssh-hull/ui/windows/tunnels/edit_window.rb +39 -0
- data/lib/ssh-hull/ui/windows/tunnels/new_window.rb +45 -0
- data/lib/ssh-hull/version.rb +17 -0
- data/lib/ssh-tunnel.rb +94 -0
- data/resources/gresources.xml +13 -0
- data/resources/ui/about_window.glade +48 -0
- data/resources/ui/application_window.glade +196 -0
- data/resources/ui/hosts/delete_window.glade +74 -0
- data/resources/ui/hosts/edit_window.glade +331 -0
- data/resources/ui/hosts/new_window.glade +328 -0
- data/resources/ui/tunnels/delete_window.glade +73 -0
- data/resources/ui/tunnels/edit_window.glade +305 -0
- data/resources/ui/tunnels/new_window.glade +305 -0
- data/snap/snapcraft.yaml +48 -0
- data/spec/factories/host.rb +22 -0
- data/spec/factories/tunnel.rb +16 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/ssh_tunnel/ui/forms/host_form_spec.rb +103 -0
- data/spec/ssh_tunnel/ui/forms/tunnel_form_spec.rb +132 -0
- data/spec/ssh_tunnel/ui/models/host_spec.rb +116 -0
- data/spec/ssh_tunnel/ui/models/tunnel_spec.rb +43 -0
- data/spec/ssh_tunnel_spec.rb +45 -0
- data/ssh-hull.gemspec +38 -0
- metadata +320 -0
data/exe/ssh-hull
ADDED
data/exe/ssh-tunnel
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ssh-hull
|
data/lib/ssh-hull/cli.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SSHTunnel
|
4
|
+
class CLI
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def parse(args = ARGV)
|
8
|
+
setup_options(args)
|
9
|
+
validate!
|
10
|
+
load_config!
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def run
|
15
|
+
compile_resources!
|
16
|
+
load_resources!
|
17
|
+
set_locales!
|
18
|
+
boot_application!
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
|
25
|
+
def setup_options(args)
|
26
|
+
@opts = parse_options(args)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def parse_options(argv)
|
31
|
+
opts = {}
|
32
|
+
@parser = option_parser(opts)
|
33
|
+
@parser.parse!(argv)
|
34
|
+
opts
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def option_parser(opts)
|
39
|
+
parser = OptionParser.new do |o|
|
40
|
+
o.on '-C', '--config PATH', 'path to YAML config file' do |arg|
|
41
|
+
opts[:config_file] = arg
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
parser.banner = 'ssh-hull [options]'
|
46
|
+
parser.on_tail '-h', '--help', 'Show help' do
|
47
|
+
puts parser
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
|
51
|
+
parser
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def validate!
|
56
|
+
if @opts[:config_file]
|
57
|
+
raise ArgumentError, "No such file #{@opts[:config_file]}" unless File.exist?(@opts[:config_file])
|
58
|
+
else
|
59
|
+
@opts[:config_file] = Pathname.new(File.expand_path('~/.config/ssh-hull/config.json'))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def load_config!
|
65
|
+
SSHTunnel.load_config(@opts[:config_file])
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def compile_resources!
|
70
|
+
cmd = [
|
71
|
+
'glib-compile-resources',
|
72
|
+
'--target', SSHTunnel.resources_bin.to_s,
|
73
|
+
'--sourcedir', SSHTunnel.resources_path.to_s,
|
74
|
+
SSHTunnel.resources_xml.to_s
|
75
|
+
]
|
76
|
+
system(*cmd)
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
def load_resources!
|
81
|
+
resources = Gio::Resource.load(SSHTunnel.resources_bin.to_s)
|
82
|
+
Gio::Resources.register(resources)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def set_locales!
|
87
|
+
I18n::Backend::Simple.include(I18n::Backend::Fallbacks)
|
88
|
+
I18n.load_path << Dir[SSHTunnel.locales_path]
|
89
|
+
|
90
|
+
I18n.enforce_available_locales = false
|
91
|
+
I18n.available_locales = %i[en fr]
|
92
|
+
I18n.default_locale = SSHTunnel.current_locale
|
93
|
+
I18n.fallbacks = [:en]
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def boot_application!
|
98
|
+
SSHTunnel.config.hosts.each(&:auto_start!)
|
99
|
+
app = SSHTunnel::UI::Application.new
|
100
|
+
|
101
|
+
begin
|
102
|
+
status = app.run
|
103
|
+
rescue Interrupt => e
|
104
|
+
status = 0
|
105
|
+
ensure
|
106
|
+
SSHTunnel.config.hosts.each(&:stop_tunnels!)
|
107
|
+
end
|
108
|
+
|
109
|
+
status
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SSHTunnel
|
4
|
+
module UI
|
5
|
+
class Application < Gtk::Application
|
6
|
+
|
7
|
+
attr_reader :config
|
8
|
+
|
9
|
+
|
10
|
+
# rubocop:disable Metrics/MethodLength
|
11
|
+
def initialize
|
12
|
+
super 'com.ungtb10d.ssh-hull', Gio::ApplicationFlags::FLAGS_NONE
|
13
|
+
|
14
|
+
@config = SSHTunnel.config
|
15
|
+
|
16
|
+
signal_connect :startup do |application|
|
17
|
+
quit_accels = ['<Ctrl>Q']
|
18
|
+
|
19
|
+
action = Gio::SimpleAction.new('quit')
|
20
|
+
action.signal_connect :activate do |_action, _parameter|
|
21
|
+
application.quit
|
22
|
+
end
|
23
|
+
|
24
|
+
application.add_action(action)
|
25
|
+
application.set_accels_for_action('app.quit', quit_accels)
|
26
|
+
end
|
27
|
+
|
28
|
+
signal_connect :activate do |application|
|
29
|
+
window = SSHTunnel::UI::Windows::ApplicationWindow.new(application)
|
30
|
+
window.present
|
31
|
+
|
32
|
+
# Gtk::StatusIcon is deprecated
|
33
|
+
# See: https://developer.gnome.org/gtk3/stable/GtkStatusIcon.html#gtk-status-icon-new
|
34
|
+
# SSHTunnel::UI::StatusIcon.new(application, window)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
# rubocop:enable Metrics/MethodLength
|
38
|
+
|
39
|
+
|
40
|
+
def quit
|
41
|
+
@config.hosts.map(&:stop_tunnels!)
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SSHTunnel
|
4
|
+
module UI
|
5
|
+
module Forms
|
6
|
+
class ApplicationForm
|
7
|
+
|
8
|
+
include ActiveModel::Model
|
9
|
+
include ActiveModel::Validations::Callbacks
|
10
|
+
|
11
|
+
class_attribute :attributes
|
12
|
+
|
13
|
+
attr_reader :model
|
14
|
+
|
15
|
+
class << self
|
16
|
+
|
17
|
+
def attribute(name, opts = {})
|
18
|
+
self.attributes ||= []
|
19
|
+
create_attribute(name, opts)
|
20
|
+
self.attributes += [name]
|
21
|
+
end
|
22
|
+
|
23
|
+
# rubocop:disable Layout/EmptyLinesAroundAttributeAccessor
|
24
|
+
private def create_attribute(name, opts = {})
|
25
|
+
required = opts.fetch(:required, false)
|
26
|
+
attr_accessor name
|
27
|
+
validates_presence_of(name) if required
|
28
|
+
end
|
29
|
+
# rubocop:enable Layout/EmptyLinesAroundAttributeAccessor
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def initialize(model)
|
35
|
+
@model = model
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def submit(params)
|
40
|
+
self.class.attributes.each do |attr|
|
41
|
+
if params[attr]
|
42
|
+
method = "#{attr}="
|
43
|
+
__send__(method, params[attr])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def save
|
50
|
+
self.class.attributes.each do |attr|
|
51
|
+
value = __send__(attr)
|
52
|
+
method = "#{attr}="
|
53
|
+
model.__send__(method, value)
|
54
|
+
end
|
55
|
+
model
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
|
62
|
+
def cast_to_int(value)
|
63
|
+
Integer(value) rescue value
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SSHTunnel
|
4
|
+
module UI
|
5
|
+
module Forms
|
6
|
+
class HostForm < ApplicationForm
|
7
|
+
|
8
|
+
attribute :name, required: true
|
9
|
+
attribute :user, required: true
|
10
|
+
attribute :host, required: true
|
11
|
+
attribute :port, required: true
|
12
|
+
attribute :identity_file
|
13
|
+
|
14
|
+
validates_inclusion_of :port, in: 0..65_535
|
15
|
+
|
16
|
+
# Callbacks
|
17
|
+
before_validation :cast_port_to_int
|
18
|
+
|
19
|
+
|
20
|
+
def cast_port_to_int
|
21
|
+
self.port = cast_to_int(port)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SSHTunnel
|
4
|
+
module UI
|
5
|
+
module Forms
|
6
|
+
class TunnelForm < ApplicationForm
|
7
|
+
|
8
|
+
attribute :name, required: true
|
9
|
+
attribute :type, required: true
|
10
|
+
attribute :local_host, required: true
|
11
|
+
attribute :local_port, required: true
|
12
|
+
attribute :remote_host, required: true
|
13
|
+
attribute :remote_port, required: true
|
14
|
+
attribute :auto_start
|
15
|
+
|
16
|
+
validates_inclusion_of :local_port, in: 0..65_535
|
17
|
+
validates_inclusion_of :remote_port, in: 0..65_535
|
18
|
+
|
19
|
+
# Callbacks
|
20
|
+
before_validation :cast_port_to_int
|
21
|
+
|
22
|
+
|
23
|
+
def cast_port_to_int
|
24
|
+
self.local_port = cast_to_int(local_port)
|
25
|
+
self.remote_port = cast_to_int(remote_port)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SSHTunnel
|
4
|
+
module UI
|
5
|
+
module Helpers
|
6
|
+
module ApplicationWindowHelper
|
7
|
+
|
8
|
+
include SSHTunnel::UI::Helpers::Common::MinimizeHelper
|
9
|
+
include SSHTunnel::UI::Helpers::Common::ToolbarHelper
|
10
|
+
include SSHTunnel::UI::Helpers::Common::TranslationHelper
|
11
|
+
include SSHTunnel::UI::Helpers::Common::TreeViewHelper
|
12
|
+
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
base.extend(ClassMethods)
|
16
|
+
base.extend(SSHTunnel::UI::Helpers::Common::FormHelper::ClassMethods)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
|
22
|
+
MENU_ITEMS = %w[quit about].freeze
|
23
|
+
TOOLBAR_BUTTONS = %w[add edit remove start stop].freeze
|
24
|
+
|
25
|
+
def init
|
26
|
+
bind_menu_entries(MENU_ITEMS)
|
27
|
+
bind_buttons(TOOLBAR_BUTTONS)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def load_hosts_treeview
|
34
|
+
# create treeview
|
35
|
+
treeview_model = create_hosts_treeview_model(all_hosts)
|
36
|
+
@hosts_treeview = create_hosts_treeview(treeview_model)
|
37
|
+
|
38
|
+
# Render treeview
|
39
|
+
hosts_scrolled_window.shadow_type = :etched_in
|
40
|
+
hosts_scrolled_window.set_policy(:automatic, :automatic)
|
41
|
+
hosts_scrolled_window.add(@hosts_treeview)
|
42
|
+
@hosts_treeview.show
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def reload_hosts_treeview
|
47
|
+
@hosts_treeview.destroy
|
48
|
+
load_hosts_treeview
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
|
55
|
+
HOST_STATE_COLUMN = 0
|
56
|
+
HOST_UUID_COLUMN = 1
|
57
|
+
HOST_NAME_COLUMN = 2
|
58
|
+
HOST_HOST_COLUMN = 3
|
59
|
+
HOST_USER_COLUMN = 4
|
60
|
+
HOST_PORT_COLUMN = 5
|
61
|
+
TUNNEL_NAME_COLUMN = 6
|
62
|
+
TUNNEL_TYPE_COLUMN = 7
|
63
|
+
TUNNEL_LOCAL_HOST_COLUMN = 8
|
64
|
+
TUNNEL_LOCAL_PORT_COLUMN = 9
|
65
|
+
TUNNEL_REMOTE_HOST_COLUMN = 10
|
66
|
+
TUNNEL_REMOTE_PORT_COLUMN = 11
|
67
|
+
TUNNEL_AUTO_START_COLUMN = 12
|
68
|
+
|
69
|
+
|
70
|
+
# rubocop:disable Metrics/MethodLength
|
71
|
+
def create_hosts_treeview_model(hosts)
|
72
|
+
model = Gtk::TreeStore.new(String, String, String, String, String, String, String, String, String, String, String, String, String)
|
73
|
+
|
74
|
+
hosts.each do |host|
|
75
|
+
iter = model.append(nil)
|
76
|
+
|
77
|
+
iter[HOST_STATE_COLUMN] = host.started? ? 'gtk-yes' : 'gtk-no'
|
78
|
+
iter[HOST_UUID_COLUMN] = host.uuid
|
79
|
+
iter[HOST_NAME_COLUMN] = host.name
|
80
|
+
iter[HOST_USER_COLUMN] = host.user
|
81
|
+
iter[HOST_HOST_COLUMN] = host.host
|
82
|
+
iter[HOST_PORT_COLUMN] = host.port
|
83
|
+
iter[TUNNEL_NAME_COLUMN] = ''
|
84
|
+
iter[TUNNEL_TYPE_COLUMN] = ''
|
85
|
+
iter[TUNNEL_LOCAL_HOST_COLUMN] = ''
|
86
|
+
iter[TUNNEL_LOCAL_PORT_COLUMN] = ''
|
87
|
+
iter[TUNNEL_REMOTE_HOST_COLUMN] = ''
|
88
|
+
iter[TUNNEL_REMOTE_PORT_COLUMN] = ''
|
89
|
+
iter[TUNNEL_AUTO_START_COLUMN] = ''
|
90
|
+
|
91
|
+
tunnels = host.tunnels
|
92
|
+
|
93
|
+
# add children
|
94
|
+
tunnels.each do |tunnel|
|
95
|
+
child_iter = model.append(iter)
|
96
|
+
|
97
|
+
child_iter[TUNNEL_NAME_COLUMN] = tunnel.name
|
98
|
+
child_iter[TUNNEL_TYPE_COLUMN] = tunnel.type
|
99
|
+
child_iter[TUNNEL_LOCAL_HOST_COLUMN] = tunnel.local_host
|
100
|
+
child_iter[TUNNEL_LOCAL_PORT_COLUMN] = tunnel.local_port
|
101
|
+
child_iter[TUNNEL_REMOTE_HOST_COLUMN] = tunnel.remote_host
|
102
|
+
child_iter[TUNNEL_REMOTE_PORT_COLUMN] = tunnel.remote_port
|
103
|
+
child_iter[TUNNEL_AUTO_START_COLUMN] = tunnel.auto_start?.to_s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
model
|
108
|
+
end
|
109
|
+
# rubocop:enable Metrics/MethodLength
|
110
|
+
|
111
|
+
|
112
|
+
def create_hosts_treeview(model)
|
113
|
+
treeview = Gtk::TreeView.new(model)
|
114
|
+
|
115
|
+
# configure treeview selection
|
116
|
+
# sub-rows are not clickable
|
117
|
+
treeview.selection.mode = :single
|
118
|
+
treeview.selection.set_select_function do |_selection, _model, path, _path_currentry_selected|
|
119
|
+
path.to_s.include?(':') ? false : true
|
120
|
+
end
|
121
|
+
|
122
|
+
# Disable buttons if tunnels are running
|
123
|
+
hosts_treeview_bind_single_click(treeview)
|
124
|
+
|
125
|
+
# Start host tunnels on double-click
|
126
|
+
hosts_treeview_bind_double_click(treeview)
|
127
|
+
|
128
|
+
# Popup the menu on right click
|
129
|
+
hosts_treeview_bind_right_click(treeview)
|
130
|
+
|
131
|
+
# add columns to the tree view
|
132
|
+
hosts_treeview_add_columns(treeview)
|
133
|
+
|
134
|
+
treeview
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
def hosts_treeview_bind_single_click(treeview)
|
139
|
+
treeview.selection.signal_connect :changed do
|
140
|
+
with_host_model do |object|
|
141
|
+
disable_buttons_if_tunnels_running(object)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def hosts_treeview_bind_double_click(treeview)
|
148
|
+
treeview.signal_connect :row_activated do |_widget, path|
|
149
|
+
if path.to_s.include?(':')
|
150
|
+
false
|
151
|
+
else
|
152
|
+
with_host_model do |object|
|
153
|
+
object.toggle_tunnels!
|
154
|
+
reload_hosts_treeview
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# rubocop:disable Style/SoleNestedConditional
|
162
|
+
def hosts_treeview_bind_right_click(treeview)
|
163
|
+
treeview.signal_connect :button_press_event do |widget, event|
|
164
|
+
if event.is_a?(Gdk::EventButton) && event.button == 3
|
165
|
+
if widget.selection.selected && !widget.selection.selected.path.to_s.include?(':')
|
166
|
+
# TODO: finish implementation of right click
|
167
|
+
puts 'RIGHT CLICK'
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
# rubocop:enable Style/SoleNestedConditional
|
173
|
+
|
174
|
+
|
175
|
+
def hosts_treeview_add_columns(treeview)
|
176
|
+
add_image_column treeview, t('view.host.state'), 'icon-name': HOST_STATE_COLUMN
|
177
|
+
add_text_column treeview, t('view.host.uuid'), text: HOST_UUID_COLUMN, visible: false
|
178
|
+
add_text_column treeview, t('view.host.name'), text: HOST_NAME_COLUMN
|
179
|
+
add_text_column treeview, t('view.host.user'), text: HOST_USER_COLUMN
|
180
|
+
add_text_column treeview, t('view.host.host'), text: HOST_HOST_COLUMN
|
181
|
+
add_text_column treeview, t('view.host.port'), text: HOST_PORT_COLUMN
|
182
|
+
add_text_column treeview, t('view.tunnel.name'), text: TUNNEL_NAME_COLUMN
|
183
|
+
add_text_column treeview, t('view.tunnel.type'), text: TUNNEL_TYPE_COLUMN
|
184
|
+
add_text_column treeview, t('view.tunnel.local_host'), text: TUNNEL_LOCAL_HOST_COLUMN
|
185
|
+
add_text_column treeview, t('view.tunnel.local_port'), text: TUNNEL_LOCAL_PORT_COLUMN
|
186
|
+
add_text_column treeview, t('view.tunnel.remote_host'), text: TUNNEL_REMOTE_HOST_COLUMN
|
187
|
+
add_text_column treeview, t('view.tunnel.remote_port'), text: TUNNEL_REMOTE_PORT_COLUMN
|
188
|
+
add_text_column treeview, t('view.tunnel.auto_start'), text: TUNNEL_AUTO_START_COLUMN
|
189
|
+
end
|
190
|
+
|
191
|
+
|
192
|
+
def all_hosts
|
193
|
+
@application.config.hosts
|
194
|
+
end
|
195
|
+
|
196
|
+
|
197
|
+
def find_host_model
|
198
|
+
return nil if @hosts_treeview.selection.selected.blank?
|
199
|
+
|
200
|
+
uuid = @hosts_treeview.selection.selected.get_value(HOST_UUID_COLUMN)
|
201
|
+
all_hosts.find { |h| h.uuid == uuid }
|
202
|
+
end
|
203
|
+
|
204
|
+
|
205
|
+
def with_host_model
|
206
|
+
object = find_host_model
|
207
|
+
yield object if object
|
208
|
+
end
|
209
|
+
|
210
|
+
|
211
|
+
def with_new_host_model
|
212
|
+
yield SSHTunnel::UI::Models::Host.new
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
def disable_buttons_if_tunnels_running(host)
|
217
|
+
if host.started?
|
218
|
+
button_edit.sensitive = false
|
219
|
+
button_remove.sensitive = false
|
220
|
+
button_start.sensitive = false
|
221
|
+
button_stop.sensitive = true
|
222
|
+
else
|
223
|
+
button_edit.sensitive = true
|
224
|
+
button_remove.sensitive = true
|
225
|
+
button_start.sensitive = true
|
226
|
+
button_stop.sensitive = false
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|