Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
emulab
emulab-devel
Commits
bc84ff27
Commit
bc84ff27
authored
May 30, 2014
by
Jonathon Duerig
Browse files
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
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
,