Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
emulab
emulab-devel
Commits
bc84ff27
Commit
bc84ff27
authored
May 30, 2014
by
Jonathon Duerig
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Integrate Jacks with remainder of Apt pages. Fix jquery-ui paths to point to ../images.
parent
46d6377d
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
62 additions
and
414 deletions
+62
-414
www/aptui/css/jquery-ui-1.10.4.custom.min.css
www/aptui/css/jquery-ui-1.10.4.custom.min.css
+1
-1
www/aptui/css/quickvm.css
www/aptui/css/quickvm.css
+5
-1
www/aptui/js/instantiate.js
www/aptui/js/instantiate.js
+2
-28
www/aptui/js/manage_profile.js
www/aptui/js/manage_profile.js
+2
-12
www/aptui/js/myprofiles.js
www/aptui/js/myprofiles.js
+1
-9
www/aptui/js/quickvm_sup.js
www/aptui/js/quickvm_sup.js
+35
-298
www/aptui/js/status.js
www/aptui/js/status.js
+13
-62
www/aptui/myprofiles.php
www/aptui/myprofiles.php
+1
-1
www/aptui/template/showtopo-modal.html
www/aptui/template/showtopo-modal.html
+1
-1
www/aptui/template/status.html
www/aptui/template/status.html
+1
-1
No files found.
www/aptui/css/jquery-ui-1.10.4.custom.min.css
View file @
bc84ff27
This diff is collapsed.
Click to expand it.
www/aptui/css/quickvm.css
View file @
bc84ff27
...
...
@@ -130,13 +130,17 @@ body {
}
#showtopo_nopicker
{
border
:
1px
solid
#000
;
height
:
300px
;
}
#showtopo_div
{
height
:
300px
;
}
#showtopo_statuspage
{
height
:
300px
;
}
@media
(
min-width
:
970px
)
{
#showtopo_dialog
{
...
...
www/aptui/js/instantiate.js
View file @
bc84ff27
...
...
@@ -2,13 +2,11 @@
require
(
window
.
APT_OPTIONS
.
configObject
,
[
'
underscore
'
,
'
js/quickvm_sup
'
,
// jQuery modules
'
formhelpers
'
,
'
filestyle
'
,
'
marked
'
,
'
jacks
'
],
'
formhelpers
'
,
'
filestyle
'
,
'
marked
'
],
function
(
_
,
sup
)
{
'
use strict
'
;
var
jacksInstance
;
var
jacksUpdate
;
var
ajaxurl
;
function
initialize
()
...
...
@@ -120,31 +118,7 @@ function (_, sup)
$
(
'
#showtopo_description
'
).
html
(
description
);
$
(
'
#selected_profile_description
'
).
html
(
description
);
if
(
!
jacksInstance
)
{
jacksInstance
=
new
window
.
Jacks
({
mode
:
'
viewer
'
,
source
:
'
rspec
'
,
root
:
'
#showtopo_div
'
,
// size: { x: 643, y: 300 },
nodeSelect
:
false
,
readyCallback
:
function
(
input
,
output
)
{
jacksUpdate
=
input
;
jacksUpdate
.
trigger
(
'
change-topology
'
,
[{
rspec
:
json
.
value
.
rspec
}]);
},
show
:
{
rspec
:
false
,
tour
:
false
,
version
:
false
}
});
}
else
if
(
jacksUpdate
)
{
jacksUpdate
.
trigger
(
'
change-topology
'
,
[{
rspec
:
json
.
value
.
rspec
}]);
}
sup
.
maketopmap
(
'
#showtopo_div
'
,
json
.
value
.
rspec
,
null
);
}
var
$xmlthing
=
sup
.
CallServerMethod
(
ajaxurl
,
"
instantiate
"
,
"
GetProfile
"
,
...
...
www/aptui/js/manage_profile.js
View file @
bc84ff27
...
...
@@ -121,10 +121,7 @@ function (_, sup, filesize, ShowImagingModal,
$
(
'
#showtopo_modal_button
'
).
click
(
function
(
event
)
{
event
.
preventDefault
();
// The rspec is taken from the text area.
var
xmlDoc
=
$
.
parseXML
(
$
(
'
#profile_rspec_textarea
'
).
val
());
var
xml
=
$
(
xmlDoc
);
ShowRspecTopo
(
xml
);
ShowRspecTopo
(
$
(
'
#profile_rspec_textarea
'
).
val
());
});
$
(
'
#expand_rspec_modal_button
'
).
click
(
function
(
event
)
{
$
(
'
#modal_profile_rspec_textarea
'
).
val
(
...
...
@@ -500,15 +497,8 @@ function (_, sup, filesize, ShowImagingModal,
//
function
ShowRspecTopo
(
xml
)
{
var
topo
=
sup
.
ConvertManifestToJSON
(
null
,
xml
);
console
.
info
(
topo
);
sup
.
ShowModal
(
"
#quickvm_topomodal
"
);
// Subtract -2 cause of the border.
sup
.
maketopmap
(
"
#showtopo_nopicker
"
,
(
$
(
"
#showtopo_nopicker
"
).
outerWidth
()
-
2
),
300
,
topo
,
null
);
sup
.
maketopmap
(
"
#showtopo_nopicker
"
,
xml
,
null
);
}
//
...
...
www/aptui/js/myprofiles.js
View file @
bc84ff27
...
...
@@ -59,16 +59,8 @@ function (sup)
alert
(
"
Failed to get rspec for topology viewer:
"
+
json
.
value
);
return
;
}
var
xmlDoc
=
$
.
parseXML
(
json
.
value
.
rspec
);
var
xml
=
$
(
xmlDoc
);
var
topo
=
sup
.
ConvertManifestToJSON
(
profile
,
xml
);
sup
.
ShowModal
(
"
#quickvm_topomodal
"
);
// Subtract -2 cause of the border.
sup
.
maketopmap
(
"
#showtopo_nopicker
"
,
(
$
(
"
#showtopo_nopicker
"
).
outerWidth
()
-
2
),
300
,
topo
,
null
);
sup
.
maketopmap
(
'
#showtopo_nopicker
'
,
json
.
value
.
rspec
,
null
);
};
var
$xmlthing
=
sup
.
CallServerMethod
(
ajaxurl
,
"
myprofiles
"
,
...
...
www/aptui/js/quickvm_sup.js
View file @
bc84ff27
define
([
'
d3
'
,
'
dateformat
'
,
'
marked
'
],
define
([
'
d3
'
,
'
dateformat
'
,
'
marked
'
,
'
jacks
'
],
function
(
d3
)
{
function
ShowModal
(
which
)
...
...
@@ -37,308 +37,46 @@ function CallServerMethod(url, route, method, args)
});
}
function
maketopmap
(
divname
,
width
,
height
,
json
,
sshcallback
)
{
var
ismousedown
=
false
;
var
savedTrans
;
var
savedScale
;
// Flag to distinguish between click and click/drag.
var
isDragging
=
false
;
var
change_view
=
d3
.
behavior
.
zoom
()
.
scaleExtent
([
1
,
5
])
.
on
(
"
zoom
"
,
rescaleg
);
var
jacksInstance
;
var
jacksInput
;
var
jacksOutput
;
function
rescaleg
(
d
,
i
,
j
)
{
if
(
!
ismousedown
)
function
maketopmap
(
divname
,
xml
,
sshcallback
)
{
if
(
!
jacksInstance
)
{
jacksInstance
=
new
window
.
Jacks
({
mode
:
'
viewer
'
,
source
:
'
rspec
'
,
root
:
divname
,
nodeSelect
:
false
,
readyCallback
:
function
(
input
,
output
)
{
jacksInput
=
input
;
jacksOutput
=
output
;
jacksInput
.
trigger
(
'
change-topology
'
,
[{
rspec
:
xml
}]);
if
(
sshcallback
)
{
trans
=
d3
.
event
.
translate
;
scale
=
d3
.
event
.
scale
;
tx
=
Math
.
min
(
0
,
Math
.
max
(
width
*
(
1
-
scale
),
trans
[
0
]));
ty
=
Math
.
min
(
0
,
Math
.
max
(
height
*
(
1
-
scale
),
trans
[
1
]));
change_view
.
translate
([
tx
,
ty
]);
vis
.
attr
(
"
transform
"
,
"
translate(
"
+
tx
+
"
,
"
+
ty
+
"
)
"
+
"
scale(
"
+
scale
+
"
)
"
);
}
}
function
mousedown
()
{
$
(
"
#quickvm_topomodal
"
).
addClass
(
"
unselectable
"
);
}
function
mouseup
()
{
$
(
"
#quickvm_topomodal
"
).
removeClass
(
"
unselectable
"
);
}
$
(
divname
).
html
(
"
<div></div>
"
);
var
outer
=
d3
.
select
(
divname
).
append
(
"
svg:svg
"
)
.
attr
(
"
class
"
,
"
topomap
"
)
.
style
(
"
visibility
"
,
"
hidden
"
)
.
attr
(
"
width
"
,
width
)
.
attr
(
"
height
"
,
height
)
.
attr
(
"
pointer-events
"
,
"
all
"
);
var
vis
=
outer
.
append
(
'
svg:g
'
)
.
on
(
"
dblclick.zoom
"
,
null
)
.
call
(
change_view
)
.
append
(
'
svg:g
'
)
.
on
(
"
mousedown
"
,
mousedown
)
.
on
(
"
mouseup
"
,
mouseup
);
var
rect
=
vis
.
append
(
"
svg:rect
"
)
.
attr
(
"
width
"
,
width
)
.
attr
(
"
height
"
,
height
)
.
style
(
"
fill-opacity
"
,
0.0
)
.
style
(
"
stroke
"
,
"
#000
"
);
var
topo
=
function
(
json
)
{
var
force
=
self
.
force
=
d3
.
layout
.
force
()
.
nodes
(
json
.
nodes
)
.
links
(
json
.
links
)
.
distance
(
150
)
.
charge
(
-
400
)
.
size
([
width
,
height
])
.
start
();
var
linkg
=
vis
.
selectAll
(
"
g.link
"
)
.
data
(
json
.
links
)
.
enter
().
append
(
"
svg:g
"
);
var
link
=
linkg
.
append
(
"
svg:line
"
)
.
attr
(
"
class
"
,
"
linkline
"
)
.
attr
(
"
x1
"
,
function
(
d
)
{
return
d
.
source
.
x
;
})
.
attr
(
"
y1
"
,
function
(
d
)
{
return
d
.
source
.
y
;
})
.
attr
(
"
x2
"
,
function
(
d
)
{
return
d
.
target
.
x
;
})
.
attr
(
"
y2
"
,
function
(
d
)
{
return
d
.
target
.
y
;
});
var
linklabel
=
linkg
.
append
(
"
svg:text
"
)
.
attr
(
"
class
"
,
"
linktext
"
)
.
attr
(
"
x
"
,
function
(
d
)
{
return
(
d
.
source
.
x
+
d
.
target
.
x
)
/
2
})
.
attr
(
"
y
"
,
function
(
d
)
{
return
(
d
.
source
.
y
+
d
.
target
.
y
)
/
2
})
.
text
(
function
(
d
)
{
return
d
.
name
});
var
node_drag
=
d3
.
behavior
.
drag
()
.
on
(
"
dragstart
"
,
dragstart
)
.
on
(
"
drag
"
,
dragmove
)
.
on
(
"
dragend
"
,
dragend
);
function
dragstart
(
d
,
i
)
{
// stops the force auto positioning before you start dragging
force
.
stop
()
ismousedown
=
true
;
savedTrans
=
change_view
.
translate
();
savedScale
=
change_view
.
scale
();
}
function
dragmove
(
d
,
i
)
{
d
.
px
+=
d3
.
event
.
dx
;
d
.
py
+=
d3
.
event
.
dy
;
d
.
x
+=
d3
.
event
.
dx
;
d
.
y
+=
d3
.
event
.
dy
;
// this is the key to make it work together with updating
// both px,py,x,y on d !
tick
(
null
);
}
function
dragend
(
d
,
i
)
{
// of course set the node to fixed so the force doesn't
// include the node in its auto positioning stuff
d
.
fixed
=
true
;
force
.
resume
();
ismousedown
=
false
;
change_view
.
translate
(
savedTrans
);
change_view
.
scale
(
savedScale
);
}
var
nodeg
=
vis
.
selectAll
(
"
g.node
"
)
.
data
(
json
.
nodes
)
.
enter
().
append
(
"
svg:g
"
)
.
call
(
node_drag
);
//
// The mouse events are to distinguish between click and drag.
// I found it with a Google search of course.
//
var
node
=
nodeg
.
append
(
"
svg:rect
"
)
.
attr
(
"
class
"
,
"
nodebox
"
)
.
on
(
"
mousedown
"
,
function
(
d
)
{
$
(
window
).
mousemove
(
function
()
{
isDragging
=
true
;
$
(
window
).
unbind
(
"
mousemove
"
);
});
})
.
on
(
"
mouseup
"
,
function
(
d
)
{
var
wasDragging
=
isDragging
;
isDragging
=
false
;
$
(
window
).
unbind
(
"
mousemove
"
);
if
(
!
wasDragging
&&
sshcallback
)
{
//was clicking
sshcallback
(
d
.
hostport
,
d
.
client_id
);
jacksOutput
.
on
(
'
click-event
'
,
function
(
event
)
{
if
(
event
.
type
===
'
node
'
)
{
sshcallback
(
event
.
ssh
,
event
.
client_id
);
}
});
}
})
.
attr
(
"
x
"
,
"
-10px
"
)
.
attr
(
"
y
"
,
"
-10px
"
)
.
attr
(
"
width
"
,
"
20px
"
)
.
attr
(
"
height
"
,
"
20px
"
);
var
nodelabel
=
nodeg
.
append
(
"
svg:text
"
)
.
attr
(
"
class
"
,
"
nodetext
"
)
.
attr
(
"
dx
"
,
16
)
.
attr
(
"
dy
"
,
"
.35em
"
)
.
text
(
function
(
d
)
{
return
d
.
name
});
function
tick
(
e
)
{
if
(
e
&&
e
.
alpha
<
0.05
)
{
outer
.
style
(
"
visibility
"
,
"
visible
"
)
force
.
stop
();
return
;
}
if
(
0
)
{
node
.
attr
(
"
x
"
,
function
(
d
)
{
return
d
.
x
=
Math
.
max
(
10
,
Math
.
min
(
width
-
10
,
d
.
x
));
})
.
attr
(
"
y
"
,
function
(
d
)
{
return
d
.
y
=
Math
.
max
(
10
,
Math
.
min
(
height
-
10
,
d
.
y
));
});
},
show
:
{
rspec
:
false
,
tour
:
false
,
version
:
false
}
else
{
nodeg
.
attr
(
"
transform
"
,
function
(
d
)
{
d
.
px
=
d
.
x
=
Math
.
max
(
12
,
Math
.
min
(
width
-
12
,
d
.
x
));
d
.
py
=
d
.
y
=
Math
.
max
(
12
,
Math
.
min
(
height
-
12
,
d
.
y
));
return
"
translate(
"
+
d
.
x
+
"
,
"
+
d
.
y
+
"
)
"
;
});
}
link
.
attr
(
"
x1
"
,
function
(
d
)
{
return
d
.
source
.
x
;
})
.
attr
(
"
y1
"
,
function
(
d
)
{
return
d
.
source
.
y
;
})
.
attr
(
"
x2
"
,
function
(
d
)
{
return
d
.
target
.
x
;
})
.
attr
(
"
y2
"
,
function
(
d
)
{
return
d
.
target
.
y
;
});
linklabel
.
attr
(
"
x
"
,
function
(
d
)
{
return
(
d
.
source
.
x
+
d
.
target
.
x
)
/
2
})
.
attr
(
"
y
"
,
function
(
d
)
{
return
(
d
.
source
.
y
+
d
.
target
.
y
)
/
2
});
};
force
.
on
(
"
tick
"
,
tick
);
}(
json
);
return
topo
;
}
// Avoid recalc of the layout if we already have seen it. Stash
// json here and return it if we have it.
var
saved
=
new
Object
();
//
// Convert a manifest in XML to a JSON object of nodes and links.
//
function
ConvertManifestToJSON
(
name
,
xml
)
{
if
(
name
&&
saved
[
name
])
{
return
saved
[
name
];
}
var
json
=
{
"
nodes
"
:
[],
"
links
"
:
[],
};
var
interfaces
=
new
Array
();
var
count
=
0
;
$
(
xml
).
find
(
"
node
"
).
each
(
function
(){
var
client_id
=
$
(
this
).
attr
(
"
client_id
"
);
var
jobj
=
{
"
name
"
:
client_id
};
$
(
this
).
find
(
"
interface
"
).
each
(
function
()
{
var
interface_id
=
$
(
this
).
attr
(
"
client_id
"
);
var
interface
=
new
Object
();
interface
.
client_id
=
interface_id
;
interface
.
node_id
=
client_id
;
interface
.
node_index
=
count
;
interfaces
.
push
(
interface
);
});
var
login
=
$
(
this
).
find
(
"
login
"
);
if
(
login
)
{
var
user
=
login
.
attr
(
"
username
"
);
var
host
=
login
.
attr
(
"
hostname
"
);
var
port
=
login
.
attr
(
"
port
"
);
var
sshurl
=
"
ssh://
"
+
user
+
"
@
"
+
host
+
"
:
"
+
port
+
"
/
"
;
jobj
.
client_id
=
client_id
;
jobj
.
hostport
=
host
+
"
:
"
+
port
;
jobj
.
sshurl
=
sshurl
;
}
json
.
nodes
[
count
]
=
jobj
;
count
++
;
});
$
(
xml
).
find
(
"
link
"
).
each
(
function
(){
var
client_id
=
$
(
this
).
attr
(
"
client_id
"
);
var
link_type
=
$
(
this
).
find
(
"
link_type
"
);
var
ifacerefs
=
$
(
this
).
find
(
"
interface_ref
"
);
if
(
ifacerefs
.
length
<
2
)
{
console
.
info
(
"
Oops, not enough interfaces in
"
+
client_id
);
}
else
if
(
ifacerefs
.
length
>
2
)
{
console
.
info
(
"
Oops, too many interfaces in
"
+
client_id
);
}
else
{
var
source
=
ifacerefs
[
0
];
var
target
=
ifacerefs
[
1
];
source
=
$
(
source
);
target
=
$
(
target
);
var
source_ifname
=
source
.
attr
(
"
client_id
"
);
var
target_ifname
=
target
.
attr
(
"
client_id
"
);
var
source_name
=
null
;
var
target_name
=
null
;
var
source_index
=
null
;
var
target_index
=
null
;
/*
* First we have map the client_ids to the node by
* searching all of the interfaces we put into the
* list above.
*
* Javascript does not do dictionaries. Too bad.
*/
for
(
i
=
0
;
i
<
interfaces
.
length
;
i
++
)
{
if
(
interfaces
[
i
].
client_id
==
source_ifname
)
{
source_name
=
interfaces
[
i
].
node_id
;
source_index
=
interfaces
[
i
].
node_index
;
}
if
(
interfaces
[
i
].
client_id
==
target_ifname
)
{
target_name
=
interfaces
[
i
].
node_id
;
target_index
=
interfaces
[
i
].
node_index
;
}
}
json
.
links
.
push
({
"
name
"
:
client_id
,
"
source
"
:
source_index
,
"
target
"
:
target_index
,
"
source_name
"
:
source_name
,
"
target_name
"
:
target_name
,
});
}
});
if
(
name
)
{
saved
[
name
]
=
json
;
}
return
json
;
else
if
(
jacksInput
)
{
jacksInput
.
trigger
(
'
change-topology
'
,
[{
rspec
:
xml
}]);
}
}
// Spit out the oops modal.
...
...
@@ -355,7 +93,6 @@ return {
ShowModal
:
ShowModal
,
HideModal
:
HideModal
,
CallServerMethod
:
CallServerMethod
,
ConvertManifestToJSON
:
ConvertManifestToJSON
,
maketopmap
:
maketopmap
,
SpitOops
:
SpitOops
,
};
...
...
www/aptui/js/status.js
View file @
bc84ff27
require
(
[
window
.
APT_OPTIONS
.
configObject
,
'
underscore
'
,
'
js/quickvm_sup
'
,
'
moment
'
,
'
js/image
'
,
require
(
window
.
APT_OPTIONS
.
configObject
,
[
'
underscore
'
,
'
js/quickvm_sup
'
,
'
moment
'
,
'
js/image
'
,
'
js/lib/text!template/status.html
'
,
'
js/lib/text!template/waitwait-modal.html
'
,
'
js/lib/text!template/oops-modal.html
'
,
...
...
@@ -15,7 +15,6 @@ function (_, sup, moment, ShowImagingModal,
cloneHelpString
,
snapshotHelpString
)
{
'
use strict
'
;
var
CurrentTopo
=
null
;
var
nodecount
=
0
;
var
ajaxurl
=
null
;
var
uuid
=
null
;
...
...
@@ -279,7 +278,6 @@ function (_, sup, moment, ShowImagingModal,
}
if
(
!
StatusWatchCallBack
.
active
)
{
ShowTopo
(
uuid
);
StartResizeWatchdog
()
StatusWatchCallBack
.
active
=
1
;
}
EnableButtons
();
...
...
@@ -370,41 +368,6 @@ function (_, sup, moment, ShowImagingModal,
}
}
//
// Install a window resize handler to redraw the topomap.
//
function
StartResizeWatchdog
()
{
var
resizeTimer
;
//
// This does the actual work, called from the timer.
//
function
resizeFunction
()
{
// console.info("resizing topo");
// Must clear the div for the D3 library.
$
(
"
#showtopo_statuspage
"
).
html
(
"
<div></div>
"
);
$
(
"
#showtopo_statuspage
"
).
removeClass
(
"
invisible
"
);
ReDrawTopoMap
();
}
//
// When we get (the first of a series) of resize events,
// we want to throw away the current topograph and set a
// timer that will run a little while later, to redraw
// it in the newly sized container. But, resize events might
// come pouring in as the user moves the moouse, so we just
// kill the old one each time, and eventually it will fire
// after the user stops dinking around.
//
$
(
window
).
resize
(
function
()
{
$
(
"
#showtopo_statuspage
"
).
addClass
(
"
invisible
"
);
clearTimeout
(
resizeTimer
);
resizeTimer
=
setTimeout
(
resizeFunction
,
250
);
});
}
//
// Found this with a Google search; countdown till the expiration time,
// updating the display. Watch for extension via the reset variable.
...
...
@@ -669,6 +632,9 @@ function (_, sup, moment, ShowImagingModal,
"
hostport
"
:
hostport
});
xmlthing
.
done
(
callback
);
}
var
hostportList
=
{};
//
// Show the topology inside the topo container. Called from the status
// watchdog and the resize wachdog. Replaces the current topo drawing.
...
...
@@ -676,18 +642,14 @@ function (_, sup, moment, ShowImagingModal,
function
ShowTopo
(
uuid
)
{
var
callback
=
function
(
json
)
{
// console.info(json.value);
var
xmlDoc
=
$
.
parseXML
(
json
.
value
);
var
xml
=
$
(
xmlDoc
);
var
topo
=
sup
.
ConvertManifestToJSON
(
null
,
xml
);
// console.info(json.value);
if
(
$
(
"
#manifest_textarea
"
).
length
)
{
$
(
"
#manifest_textarea
"
).
html
(
json
.
value
);
$
(
"
#manifest_textarea
"
).
css
(
"
height
"
,
"
300
"
);
}
var
xmlDoc
=
$
.
parseXML
(
json
.
value
);
var
xml
=
$
(
xmlDoc
);
// Suck the instructions out of the tour and put them into
// the Usage area.
$
(
xml
).
find
(
"
rspec_tour
"
).
each
(
function
()
{
...
...
@@ -728,6 +690,7 @@ function (_, sup, moment, ShowImagingModal,
// console.info(url);
var
hostport
=
host
+
"
:
"
+
port
;
hostportList
[
node
]
=
hostport
;
ssh
=
"
<button class='btn btn-primary btn-sm'
"
+
"
id='
"
+
"
sshbutton_
"
+
node
+
"
'
"
+
"
type='button'>
"
+
...
...
@@ -752,10 +715,11 @@ function (_, sup, moment, ShowImagingModal,
nodecount
++
;
});
// Stash this for resize watchdog redraw.
CurrentTopo
=
topo
;
ReDrawTopoMap
();
$
(
"
#showtopo_container
"
).
removeClass
(
"
invisible
"
);
$
(
'
#quicktabs a[href="#profile"]
'
).
tab
(
'
show
'
);
sup
.
maketopmap
(
'
#showtopo_statuspage
'
,
json
.
value
,
function
(
ssh
,
clientId
)
{
NewSSHTab
(
hostportList
[
clientId
],
clientId
);
});
// If a single node, show the clone button. Only
// single node experiments can do this.
...
...
@@ -778,19 +742,6 @@ function (_, sup, moment, ShowImagingModal,
xmlthing
.
done
(
callback
);
}
function
ReDrawTopoMap
()
{
// Activate the "profile" tab or else the map has no size.
$
(
'
#quicktabs a[href="#profile"]
'
).
tab
(
'
show
'
);
// Subtract -2 cause of the border.
sup
.
maketopmap
(
"
#showtopo_statuspage
"
,
$
(
"
#showtopo_statuspage
"
).
outerWidth
()
-
2
,
300
,
CurrentTopo
,
// Callback for ssh.
function
(
arg1
,
arg2
)
{
NewSSHTab
(
arg1
,
arg2
);