oxidized-web 0.13.1 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of oxidized-web might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.github/PULL_REQUEST_TEMPLATE.md +12 -0
- data/.github/dependabot.yml +25 -0
- data/.github/workflows/codeql.yml +76 -0
- data/.github/workflows/ruby.yml +42 -0
- data/.github/workflows/stale.yml +18 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +38 -3
- data/.rubocop_todo.yml +28 -207
- data/CHANGELOG.md +28 -0
- data/README.md +8 -5
- data/Rakefile +48 -5
- data/docs/development.md +170 -0
- data/lib/oxidized/web/mig.rb +37 -47
- data/lib/oxidized/web/public/css/oxidized.css +59 -0
- data/lib/oxidized/web/public/scripts/oxidized.js +1 -12
- data/lib/oxidized/web/public/weblibs/bootstrap-icons.css +2078 -0
- data/lib/oxidized/web/public/weblibs/bootstrap.bundle.js +6314 -0
- data/lib/oxidized/web/public/weblibs/bootstrap.bundle.js.map +1 -0
- data/lib/oxidized/web/public/weblibs/bootstrap.css +12057 -0
- data/lib/oxidized/web/public/weblibs/bootstrap.css.map +1 -0
- data/lib/oxidized/web/public/weblibs/bootstrap.js +4494 -0
- data/lib/oxidized/web/public/weblibs/bootstrap.js.map +1 -0
- data/lib/oxidized/web/public/weblibs/buttons.bootstrap5.css +398 -0
- data/lib/oxidized/web/public/weblibs/buttons.bootstrap5.js +117 -0
- data/lib/oxidized/web/public/weblibs/buttons.colVis.js +256 -0
- data/lib/oxidized/web/public/weblibs/dataTables.bootstrap5.css +487 -0
- data/lib/oxidized/web/public/weblibs/dataTables.bootstrap5.js +147 -0
- data/lib/oxidized/web/public/weblibs/dataTables.buttons.js +2820 -0
- data/lib/oxidized/web/public/weblibs/dataTables.js +13171 -0
- data/lib/oxidized/web/public/weblibs/fonts/bootstrap-icons.woff +0 -0
- data/lib/oxidized/web/public/weblibs/fonts/bootstrap-icons.woff2 +0 -0
- data/lib/oxidized/web/public/weblibs/jquery.js +10716 -0
- data/lib/oxidized/web/version.rb +7 -0
- data/lib/oxidized/web/views/conf_search.haml +14 -13
- data/lib/oxidized/web/views/diffs.haml +5 -5
- data/lib/oxidized/web/views/footer.haml +5 -4
- data/lib/oxidized/web/views/head.haml +21 -7
- data/lib/oxidized/web/views/layout.haml +29 -34
- data/lib/oxidized/web/views/migration.haml +7 -0
- data/lib/oxidized/web/views/node.haml +10 -8
- data/lib/oxidized/web/views/nodes.haml +45 -35
- data/lib/oxidized/web/views/stats.haml +32 -24
- data/lib/oxidized/web/views/version.haml +8 -6
- data/lib/oxidized/web/views/versions.haml +23 -24
- data/lib/oxidized/web/webapp.rb +106 -87
- data/lib/oxidized/web.rb +10 -7
- data/oxidized-web.gemspec +27 -14
- data/package-lock.json +104 -0
- data/package.json +21 -0
- data/spec/node_spec.rb +143 -0
- data/spec/root_spec.rb +18 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/webapp_spec.rb +28 -0
- metadata +187 -73
- data/lib/oxidized/web/public/css/bootstrap.min.css +0 -5
- data/lib/oxidized/web/public/css/buttons.bootstrap.min.css +0 -1
- data/lib/oxidized/web/public/css/dataTables.bootstrap.css +0 -299
- data/lib/oxidized/web/public/css/dataTables.colVis.css +0 -171
- data/lib/oxidized/web/public/css/oxidized_custom.css +0 -19
- data/lib/oxidized/web/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/lib/oxidized/web/public/fonts/glyphicons-halflings-regular.svg +0 -229
- data/lib/oxidized/web/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/lib/oxidized/web/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/lib/oxidized/web/public/images/diff_15x17.png +0 -0
- data/lib/oxidized/web/public/images/sort_asc.png +0 -0
- data/lib/oxidized/web/public/images/sort_asc_disabled.png +0 -0
- data/lib/oxidized/web/public/images/sort_both.png +0 -0
- data/lib/oxidized/web/public/images/sort_desc.png +0 -0
- data/lib/oxidized/web/public/images/sort_desc_disabled.png +0 -0
- data/lib/oxidized/web/public/images/versioning_18px.png +0 -0
- data/lib/oxidized/web/public/scripts/bootstrap.min.js +0 -6
- data/lib/oxidized/web/public/scripts/dataTables.bootstrap.js +0 -186
- data/lib/oxidized/web/public/scripts/dataTables.colVis.js +0 -1123
- data/lib/oxidized/web/public/scripts/jquery-2.1.1.min.js +0 -4
- data/lib/oxidized/web/public/scripts/jquery.dataTables.min.js +0 -157
- data/lib/oxidized/web/public/scripts/jquery.min.js +0 -6
- data/lib/oxidized/web/views/sass/oxidized.sass +0 -113
data/docs/development.md
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
# Index
|
2
|
+
1. [Run from git](#how-to-run--develop-oxidized-web-from-git)
|
3
|
+
2. [Update weblibs](#update-the-weblibs)
|
4
|
+
3. [Release](#how-to-release-a-new-version-of-oxidized-web)
|
5
|
+
|
6
|
+
# How to run / develop oxidized-web from git
|
7
|
+
## Using the latest oxidized package
|
8
|
+
When you develop oxidized-web, it is quite simple to run it from git. As it depends on oxidized,
|
9
|
+
oxidized will be included in `bundle install`, and you just have to run `bundle exec oxidized`.
|
10
|
+
You need bundler, if not installed yet. On debian-based systems, you can run `sudo apt install ruby-bundler` to install it.
|
11
|
+
|
12
|
+
All steps in one to copy & pase:
|
13
|
+
```shell
|
14
|
+
git clone git@github.com:ytti/oxidized-web.git
|
15
|
+
cd oxidized-web
|
16
|
+
bundle config set --local path 'vendor/bundle'
|
17
|
+
bundle install
|
18
|
+
bundle exec oxidized
|
19
|
+
```
|
20
|
+
|
21
|
+
Changes to haml templates are reloaded on the fly. For changes to the ruby
|
22
|
+
scripts, you have to stop an restart `bundle exec oxidized`.
|
23
|
+
|
24
|
+
## Paralell development between oxidized and oxidized-web
|
25
|
+
You may need to make some changes in oxidized **and** oxidized-web. For this,
|
26
|
+
git clone oxidized and oxidized-web in a common root directory, add the direct
|
27
|
+
dependency to ../oxidized-web in oxidized and run oxidized from the oxidized
|
28
|
+
repo:
|
29
|
+
|
30
|
+
```shell
|
31
|
+
git clone git@github.com:ytti/oxidized-web.git
|
32
|
+
git clone git@github.com:ytti/oxidized.git
|
33
|
+
cd oxidized
|
34
|
+
bundle config set --local path 'vendor/bundle'
|
35
|
+
echo "gem 'oxidized-web', path: '../oxidized-web'" >> Gemfile
|
36
|
+
bundle install
|
37
|
+
bundle exec bin/oxidized
|
38
|
+
```
|
39
|
+
|
40
|
+
Be careful when commiting your work in oxidized *NOT* to include the changes to
|
41
|
+
Gemfile, as this is a local change for development. I (@robertcheramy) didn't
|
42
|
+
find a better way to do this, better ideas are welcome :-)
|
43
|
+
|
44
|
+
If your changes to oxidized **AND** oxidzed-web are dependent from another, make
|
45
|
+
sure you document this in the respectives CHANGELOG.md, so that everyone is
|
46
|
+
informed at the next release.
|
47
|
+
|
48
|
+
# Update the weblibs
|
49
|
+
The weblibs are beeing downloaded and maintained by `npm`.
|
50
|
+
|
51
|
+
Run `npm install` to download the weblibs. They will be stored under
|
52
|
+
`node_modules`.
|
53
|
+
The file `package-lock.json` (wich is tracked in git) ensures that every
|
54
|
+
developer gets the same versions.
|
55
|
+
|
56
|
+
Run `npm outdated` to get a list of new releases:
|
57
|
+
|
58
|
+
```shell
|
59
|
+
oxidized-web$ npm outdated
|
60
|
+
Package Current Wanted Latest Location Depended by
|
61
|
+
datatables.net-bs5 2.0.7 2.0.8 2.0.8 node_modules/datatables.net-bs5 oxidized-web
|
62
|
+
```
|
63
|
+
|
64
|
+
Run `npm update` to get the latest releases. They still are not used
|
65
|
+
oxidzed-web. Run `rake weblibs` to sync `node_modules` with
|
66
|
+
`lib/oxidized/web/public/weblibs`.
|
67
|
+
|
68
|
+
Test, and commit the changes to the weblibs **and** package-lock.json. Don't
|
69
|
+
forget to document your changes in CHANGELOG.md.
|
70
|
+
|
71
|
+
# How to release a new version of Oxidized-web?
|
72
|
+
|
73
|
+
## Review changes
|
74
|
+
Run `git diff 0.xx.yy..master` (where `0.xx.yy` is to be changed to the last
|
75
|
+
release) and review all the changes that have been done. Have a specific look
|
76
|
+
at changes you don't understand.
|
77
|
+
|
78
|
+
It is nicer to read in a GUI, so you can use something like
|
79
|
+
`git difftool --tool=kdiff3 -d 0.xx.yy..master` to see it in kdiff3.
|
80
|
+
|
81
|
+
## Update the gem dependencies to the latest versions
|
82
|
+
```
|
83
|
+
bundle outaded
|
84
|
+
bundle update
|
85
|
+
bundle outaded
|
86
|
+
```
|
87
|
+
|
88
|
+
Retest after updating!
|
89
|
+
|
90
|
+
## Update the weblibs to the latest versions
|
91
|
+
```
|
92
|
+
npm outdated
|
93
|
+
```
|
94
|
+
|
95
|
+
Retest after updating!
|
96
|
+
|
97
|
+
## Update rubocup .rubocop_todo.yml
|
98
|
+
Run `bundle exec rubocop --auto-gen-config`,
|
99
|
+
and make sure `bundle exec rake` passes after it.
|
100
|
+
|
101
|
+
If you change some code => Restart the release process at the beginning ;-)
|
102
|
+
|
103
|
+
## Make sure the file permissions are correct
|
104
|
+
Run `bundle exec rake chmod`
|
105
|
+
|
106
|
+
## Test, test test!
|
107
|
+
Run `bundle exec rake` on the git repository to check the code against rubocop and rund the
|
108
|
+
defined tests in `/spec`.
|
109
|
+
|
110
|
+
Run Oxidized-web from git against the latest Oxidized version `bundle exec oxdized`
|
111
|
+
|
112
|
+
Run Oxidized-web from git against the latest git of Oxidized (see above).
|
113
|
+
|
114
|
+
Do not integrate late PRs into master if they do not fix issues for the release. The must wait for the next release.
|
115
|
+
|
116
|
+
## Version numbering
|
117
|
+
Oxidized-web versions are nummered like 0.major.minor
|
118
|
+
- major is incremented when releasing new features. minor is then set to 0
|
119
|
+
- minor is incremented when releasing fixes only, just after a major version.
|
120
|
+
|
121
|
+
## Release
|
122
|
+
1. Checkout the master branch of oxidized-web. Make sure you are up to date with origin.
|
123
|
+
2. Change the version in lib/oxidized/web/version.rb
|
124
|
+
3. Change CHANGELOG.md to replace [Unreleased] with [0.xx.yy – 202Y-MM-DD]
|
125
|
+
4. Run `git diff` to check your changes
|
126
|
+
5. Commit the changes to the local git repository with a commit message “chore(release): release version 0.xx.yy”
|
127
|
+
6. Tag the commit with `git tag -a 0.xx.yy -m "Release 0.xx.yy"`
|
128
|
+
7. Build the gem with ‘rake build’
|
129
|
+
8. Install an test the gem locally:
|
130
|
+
```
|
131
|
+
gem install --user-install pkg/oxidized-web-0.xx.yy.gem
|
132
|
+
~/.local/share/gem/ruby/3.1.0/bin/oxidized
|
133
|
+
```
|
134
|
+
## Release in github
|
135
|
+
1. Push the commit and the tag to github:
|
136
|
+
```
|
137
|
+
git push
|
138
|
+
git push origin 0.xx.yy
|
139
|
+
```
|
140
|
+
|
141
|
+
2. Make a release from the tag in github
|
142
|
+
- Thank the contributors
|
143
|
+
- Only describe major changes, and refer to CHANGELOG.md
|
144
|
+
- List new contributors (generated automatically)
|
145
|
+
|
146
|
+
## Release in rubygems
|
147
|
+
Push the gem with ‘rake push’
|
148
|
+
|
149
|
+
You need an account at rubygems which is allowed to push oxidized
|
150
|
+
|
151
|
+
## Release in docker.io
|
152
|
+
The OCI-Containter is automatically build and pushed to docker.io by github
|
153
|
+
|
154
|
+
## Update CHANGELOG.md for next release
|
155
|
+
Add
|
156
|
+
```
|
157
|
+
## [Unreleased]
|
158
|
+
|
159
|
+
### Added
|
160
|
+
|
161
|
+
### Changed
|
162
|
+
|
163
|
+
### Fixed
|
164
|
+
|
165
|
+
```
|
166
|
+
And push to github
|
167
|
+
|
168
|
+
## Congratulate yourself
|
169
|
+
Great job! Treat yourself to your favorite drink, you deserve it!
|
170
|
+
|
data/lib/oxidized/web/mig.rb
CHANGED
@@ -9,7 +9,7 @@ module Oxidized
|
|
9
9
|
|
10
10
|
# read cloginrc and return a hash with node name, which a hash value which contains user,
|
11
11
|
# password, eventually enable
|
12
|
-
def cloginrc
|
12
|
+
def cloginrc(clogin_file)
|
13
13
|
close_file = clogin_file
|
14
14
|
file = close_file.read
|
15
15
|
file = file.gsub('add', '')
|
@@ -17,24 +17,20 @@ module Oxidized
|
|
17
17
|
hash = {}
|
18
18
|
file.each_line do |line|
|
19
19
|
# stock all device name, and password and enable if there is one
|
20
|
-
line = line.split
|
21
|
-
|
20
|
+
line = line.split
|
21
|
+
(0..line.length).each do |i|
|
22
22
|
if line[i] == 'user'
|
23
23
|
# add the equipment and user if not exist
|
24
|
-
unless hash[line[i + 1]]
|
25
|
-
hash[line[i + 1]] = { user: line[i + 2] }
|
26
|
-
end
|
24
|
+
hash[line[i + 1]] = { user: line[i + 2] } unless hash[line[i + 1]]
|
27
25
|
# if the equipment exist, add password and enable password
|
28
26
|
elsif line[i] == 'password'
|
29
27
|
if hash[line[i + 1]]
|
30
28
|
if line.length > i + 2
|
31
29
|
h = hash[line[i + 1]]
|
32
30
|
h[:password] = line[i + 2]
|
33
|
-
if /\s*/.match(line[i + 3])
|
34
|
-
h[:enable] = line[i + 3]
|
35
|
-
end
|
31
|
+
h[:enable] = line[i + 3] if /\s*/.match(line[i + 3])
|
36
32
|
hash[line[i + 1]] = h
|
37
|
-
elsif line.length
|
33
|
+
elsif line.length == i + 2
|
38
34
|
h = hash[line[i + 1]]
|
39
35
|
h[:password] = line[i + 2]
|
40
36
|
hash[line[i + 1]] = h
|
@@ -47,17 +43,15 @@ module Oxidized
|
|
47
43
|
hash
|
48
44
|
end
|
49
45
|
|
50
|
-
def model_dico
|
46
|
+
def model_dico(model)
|
51
47
|
dico = { 'cisco' => 'ios', 'foundry' => 'ironware' }
|
52
48
|
model = model.gsub("\n", '')
|
53
|
-
if dico[model]
|
54
|
-
model = dico[model]
|
55
|
-
end
|
49
|
+
model = dico[model] if dico[model]
|
56
50
|
model
|
57
51
|
end
|
58
52
|
|
59
53
|
# add node and group for an equipment (take a list of router.db)
|
60
|
-
def rancid_group
|
54
|
+
def rancid_group(router_db_list)
|
61
55
|
model = {}
|
62
56
|
hash = cloginrc @cloginrc
|
63
57
|
router_db_list.each do |router_db|
|
@@ -70,20 +64,20 @@ module Oxidized
|
|
70
64
|
file.each_line do |line|
|
71
65
|
line = line.split(':')
|
72
66
|
node = line[0]
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
67
|
+
next unless hash[node]
|
68
|
+
|
69
|
+
h = hash[node]
|
70
|
+
model = model_dico line[1].to_s
|
71
|
+
h[:model] = model
|
72
|
+
h[:group] = group
|
79
73
|
end
|
80
74
|
file_close.close
|
81
75
|
end
|
82
76
|
hash
|
83
77
|
end
|
84
|
-
|
78
|
+
|
85
79
|
# write a router.db conf, need the hash and the path of the file we whish create
|
86
|
-
def write_router_db
|
80
|
+
def write_router_db(hash)
|
87
81
|
router_db = File.new(@path_new_router, 'w')
|
88
82
|
hash.each do |key, value|
|
89
83
|
line = key.to_s
|
@@ -91,15 +85,13 @@ module Oxidized
|
|
91
85
|
line += ":#{value[:user]}"
|
92
86
|
line += ":#{value[:password]}"
|
93
87
|
line += ":#{value[:group]}"
|
94
|
-
if value[:enable]
|
95
|
-
line += ":#{value[:enable]}"
|
96
|
-
end
|
88
|
+
line += ":#{value[:enable]}" if value[:enable]
|
97
89
|
router_db.puts(line)
|
98
90
|
end
|
99
91
|
router_db.close
|
100
92
|
end
|
101
93
|
|
102
|
-
def edit_conf_file
|
94
|
+
def edit_conf_file(path_conf, router_db_path)
|
103
95
|
file_close = File.open(path_conf, 'r')
|
104
96
|
file = file_close
|
105
97
|
file = file.read
|
@@ -107,29 +99,27 @@ module Oxidized
|
|
107
99
|
new_file = []
|
108
100
|
file.each_line do |line|
|
109
101
|
if source_reached
|
110
|
-
unless /^\w/.match(line)
|
111
|
-
next
|
112
|
-
end
|
102
|
+
next unless /^\w/.match(line)
|
113
103
|
|
114
104
|
source_reached = false
|
115
105
|
end
|
116
106
|
new_file.push(line)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
107
|
+
next unless /source:/.match(line)
|
108
|
+
|
109
|
+
source_reached = true
|
110
|
+
new_file.push(" default: csv\n")
|
111
|
+
new_file.push(" csv:\n")
|
112
|
+
new_file.push(" file: #{router_db_path}\n")
|
113
|
+
new_file.push(" delimiter: !ruby/regexp /:/\n")
|
114
|
+
new_file.push(" map:\n")
|
115
|
+
new_file.push(" name: 0\n")
|
116
|
+
new_file.push(" model: 1\n")
|
117
|
+
new_file.push(" username: 2\n")
|
118
|
+
new_file.push(" password: 3\n")
|
119
|
+
new_file.push(" group: 4\n")
|
120
|
+
new_file.push(" vars_map:\n")
|
121
|
+
new_file.push(" enable: 5\n")
|
122
|
+
next
|
133
123
|
end
|
134
124
|
file_close.close
|
135
125
|
|
@@ -143,7 +133,7 @@ module Oxidized
|
|
143
133
|
def go_rancid_migration
|
144
134
|
hash = rancid_group @hash_router_db
|
145
135
|
write_router_db hash
|
146
|
-
edit_conf_file "#{
|
136
|
+
edit_conf_file "#{Dir.home}/.config/oxidized/config", @path_new_router
|
147
137
|
end
|
148
138
|
end
|
149
139
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
/* Display status of device in /nodes and /stats */
|
2
|
+
.status, .success, .no_connection, .never {
|
3
|
+
float: right;
|
4
|
+
width: 15px;
|
5
|
+
height: 15px;
|
6
|
+
border: 1px solid;
|
7
|
+
margin-right: 70%;
|
8
|
+
margin-bottom: 0px;
|
9
|
+
border-radius: 2px; }
|
10
|
+
|
11
|
+
.success {
|
12
|
+
background-color: #64FE2E; }
|
13
|
+
|
14
|
+
.no_connection {
|
15
|
+
background-color: #FF0000; }
|
16
|
+
|
17
|
+
.never {
|
18
|
+
background-color: #58ACFA; }
|
19
|
+
|
20
|
+
/* node/version/diffs */
|
21
|
+
.added {
|
22
|
+
background-color: #DBFFDB; }
|
23
|
+
|
24
|
+
.deleted {
|
25
|
+
background-color: #FFDDDD; }
|
26
|
+
|
27
|
+
|
28
|
+
.diff-index {
|
29
|
+
background-color: #FFFF99; }
|
30
|
+
|
31
|
+
.diff-empty {
|
32
|
+
background-color: #F0F0F0; }
|
33
|
+
|
34
|
+
.diffs, .diffs_old, .diffs_new {
|
35
|
+
background-color: #FAFAFA;
|
36
|
+
border: 2px solid #ccc;
|
37
|
+
border-radius: 5px;
|
38
|
+
padding: 3px;
|
39
|
+
font-family: Consolas, "Lucida Console", monospace;
|
40
|
+
white-space: pre; }
|
41
|
+
|
42
|
+
.diffs_old {
|
43
|
+
float: left;
|
44
|
+
width: 49%;
|
45
|
+
overflow: auto; }
|
46
|
+
|
47
|
+
.diffs_new {
|
48
|
+
margin-left: 51%;
|
49
|
+
width: 49%;
|
50
|
+
overflow: auto; }
|
51
|
+
|
52
|
+
.old_version_title {
|
53
|
+
float: left;
|
54
|
+
width: 49%;
|
55
|
+
font-weight: bold; }
|
56
|
+
|
57
|
+
.new_version_title {
|
58
|
+
margin-left: 51%;
|
59
|
+
font-weight: bold; }
|
@@ -25,16 +25,6 @@ var onFileSelected = function() {
|
|
25
25
|
});
|
26
26
|
};
|
27
27
|
|
28
|
-
// fix colvis buttons
|
29
|
-
var fixColVisBtn = function() {
|
30
|
-
$('.ColVis_Button').each(function() {
|
31
|
-
$(this).addClass('btn btn-default');
|
32
|
-
});
|
33
|
-
$('.ColVis_MasterButton').each(function() {
|
34
|
-
$(this).addClass('pull-right');
|
35
|
-
});
|
36
|
-
};
|
37
|
-
|
38
28
|
var convertTime = function() {
|
39
29
|
/* Convert UTC times to local browser times
|
40
30
|
* Requires that the times on the server are UTC
|
@@ -53,14 +43,13 @@ var convertTime = function() {
|
|
53
43
|
var hour = ("0" + date.getHours()).slice(-2);
|
54
44
|
var minute = ("0" + date.getMinutes()).slice(-2);
|
55
45
|
var second = ("0" + date.getSeconds()).slice(-2);
|
56
|
-
var timeZone = date.toString().match(
|
46
|
+
var timeZone = date.toString().match(/[A-Z]{3,4}[+-][0-9]{4}/)[0];
|
57
47
|
$(this).text(year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second + ' ' + timeZone);
|
58
48
|
});
|
59
49
|
};
|
60
50
|
|
61
51
|
$(function() {
|
62
52
|
onFileSelected();
|
63
|
-
fixColVisBtn();
|
64
53
|
convertTime();
|
65
54
|
// Add a row to the migration form
|
66
55
|
$("#add").click(function() {
|