ssh-hull 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|