forked from p34709852/monkey
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
2f1e690c21
|
@ -1,810 +0,0 @@
|
|||
.vis .overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
/* Must be displayed above for example selected Timeline items */
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.vis-active {
|
||||
box-shadow: 0 0 10px #86d5f8;
|
||||
}
|
||||
|
||||
/* override some bootstrap styles screwing up the timelines css */
|
||||
|
||||
.vis [class*="span"] {
|
||||
min-height: 0;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.vis.timeline {
|
||||
}
|
||||
|
||||
|
||||
.vis.timeline.root {
|
||||
position: relative;
|
||||
border: 1px solid #bfbfbf;
|
||||
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel {
|
||||
position: absolute;
|
||||
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel.center,
|
||||
.vis.timeline .vispanel.left,
|
||||
.vis.timeline .vispanel.right,
|
||||
.vis.timeline .vispanel.top,
|
||||
.vis.timeline .vispanel.bottom {
|
||||
border: 1px #bfbfbf;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel.center,
|
||||
.vis.timeline .vispanel.left,
|
||||
.vis.timeline .vispanel.right {
|
||||
border-top-style: solid;
|
||||
border-bottom-style: solid;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel.center,
|
||||
.vis.timeline .vispanel.top,
|
||||
.vis.timeline .vispanel.bottom {
|
||||
border-left-style: solid;
|
||||
border-right-style: solid;
|
||||
}
|
||||
|
||||
.vis.timeline .background {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel > .content {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel .shadow {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.8);
|
||||
/* TODO: find a nice way to ensure shadows are drawn on top of items
|
||||
z-index: 1;
|
||||
*/
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel .shadow.top {
|
||||
top: -1px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel .shadow.bottom {
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.vis.timeline .labelset {
|
||||
position: relative;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis.timeline .labelset .vlabel {
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
color: #4d4d4d;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis.timeline .labelset .vlabel {
|
||||
border-bottom: 1px solid #bfbfbf;
|
||||
}
|
||||
|
||||
.vis.timeline .labelset .vlabel:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.vis.timeline .labelset .vlabel .inner {
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.vis.timeline .labelset .vlabel .inner.hidden {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
||||
.vis.timeline .itemset {
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis.timeline .itemset .background,
|
||||
.vis.timeline .itemset .foreground {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.vis.timeline .axis {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.vis.timeline .foreground .group {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
border-bottom: 1px solid #bfbfbf;
|
||||
}
|
||||
|
||||
.vis.timeline .foreground .group:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
|
||||
.vis.timeline .item {
|
||||
position: absolute;
|
||||
color: #1A1A1A;
|
||||
border-color: #97B0F8;
|
||||
border-width: 1px;
|
||||
background-color: #D5DDF6;
|
||||
display: inline-block;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.vis.timeline .item.selected {
|
||||
border-color: #FFC200;
|
||||
background-color: #FFF785;
|
||||
|
||||
/* z-index must be higher than the z-index of custom time bar and current time bar */
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.vis.timeline .editable .item.selected {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.vis.timeline .item.point.selected {
|
||||
background-color: #FFF785;
|
||||
}
|
||||
|
||||
.vis.timeline .item.box {
|
||||
text-align: center;
|
||||
border-style: solid;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.vis.timeline .item.point {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.vis.timeline .item.dot {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
border-width: 4px;
|
||||
border-style: solid;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.vis.timeline .item.range {
|
||||
border-style: solid;
|
||||
border-radius: 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vis.timeline .item.background {
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
background-color: rgba(213, 221, 246, 0.4);
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vis.timeline .item.range .content {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis.timeline .item.background .content {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.vis.timeline .item.line {
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
border-left-width: 1px;
|
||||
border-left-style: solid;
|
||||
}
|
||||
|
||||
.vis.timeline .item .content {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis.timeline .item .delete {
|
||||
background: url('img/timeline/delete.png') no-repeat top center;
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
top: 0;
|
||||
right: -24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vis.timeline .item.range .drag-left {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
max-width: 20%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: -4px;
|
||||
|
||||
cursor: w-resize;
|
||||
}
|
||||
|
||||
.vis.timeline .item.range .drag-right {
|
||||
position: absolute;
|
||||
width: 24px;
|
||||
max-width: 20%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
right: -4px;
|
||||
|
||||
cursor: e-resize;
|
||||
}
|
||||
|
||||
.vis.timeline .timeaxis {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.vis.timeline .timeaxis.foreground {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vis.timeline .timeaxis.background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vis.timeline .timeaxis .text {
|
||||
position: absolute;
|
||||
color: #4d4d4d;
|
||||
padding: 3px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.vis.timeline .timeaxis .text.measure {
|
||||
position: absolute;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.vis.timeline .timeaxis .grid.vertical {
|
||||
position: absolute;
|
||||
border-left: 1px solid;
|
||||
}
|
||||
|
||||
.vis.timeline .timeaxis .grid.minor {
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.vis.timeline .timeaxis .grid.major {
|
||||
border-color: #bfbfbf;
|
||||
}
|
||||
|
||||
.vis.timeline .currenttime {
|
||||
background-color: #FF7F6E;
|
||||
width: 2px;
|
||||
z-index: 1;
|
||||
}
|
||||
.vis.timeline .customtime {
|
||||
background-color: #6E94FF;
|
||||
width: 2px;
|
||||
cursor: move;
|
||||
z-index: 1;
|
||||
}
|
||||
.vis.timeline.root {
|
||||
/*
|
||||
-webkit-transition: height .4s ease-in-out;
|
||||
transition: height .4s ease-in-out;
|
||||
*/
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel {
|
||||
/*
|
||||
-webkit-transition: height .4s ease-in-out, top .4s ease-in-out;
|
||||
transition: height .4s ease-in-out, top .4s ease-in-out;
|
||||
*/
|
||||
}
|
||||
|
||||
.vis.timeline .axis {
|
||||
/*
|
||||
-webkit-transition: top .4s ease-in-out;
|
||||
transition: top .4s ease-in-out;
|
||||
*/
|
||||
}
|
||||
|
||||
/* TODO: get animation working nicely
|
||||
|
||||
.vis.timeline .item {
|
||||
-webkit-transition: top .4s ease-in-out;
|
||||
transition: top .4s ease-in-out;
|
||||
}
|
||||
|
||||
.vis.timeline .item.line {
|
||||
-webkit-transition: height .4s ease-in-out, top .4s ease-in-out;
|
||||
transition: height .4s ease-in-out, top .4s ease-in-out;
|
||||
}
|
||||
/**/
|
||||
|
||||
.vis.timeline .vispanel.background.horizontal .grid.horizontal {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
border-bottom: 1px solid;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel.background.horizontal .grid.minor {
|
||||
border-color: #e5e5e5;
|
||||
}
|
||||
|
||||
.vis.timeline .vispanel.background.horizontal .grid.major {
|
||||
border-color: #bfbfbf;
|
||||
}
|
||||
|
||||
|
||||
.vis.timeline .dataaxis .yAxis.major {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
color: #4d4d4d;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.vis.timeline .dataaxis .yAxis.major.measure{
|
||||
padding: 0px 0px 0px 0px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
border: 0px;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
|
||||
.vis.timeline .dataaxis .yAxis.minor{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
color: #bebebe;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.vis.timeline .dataaxis .yAxis.minor.measure{
|
||||
padding: 0px 0px 0px 0px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
border: 0px;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.vis.timeline .dataaxis .yAxis.title{
|
||||
position: absolute;
|
||||
color: #4d4d4d;
|
||||
white-space: nowrap;
|
||||
bottom: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vis.timeline .dataaxis .yAxis.title.measure{
|
||||
padding: 0px 0px 0px 0px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
visibility: hidden;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.vis.timeline .dataaxis .yAxis.title.left {
|
||||
bottom: 0px;
|
||||
-webkit-transform-origin: left top;
|
||||
-moz-transform-origin: left top;
|
||||
-ms-transform-origin: left top;
|
||||
-o-transform-origin: left top;
|
||||
transform-origin: left bottom;
|
||||
-webkit-transform: rotate(-90deg);
|
||||
-moz-transform: rotate(-90deg);
|
||||
-ms-transform: rotate(-90deg);
|
||||
-o-transform: rotate(-90deg);
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.vis.timeline .dataaxis .yAxis.title.right {
|
||||
bottom: 0px;
|
||||
-webkit-transform-origin: right bottom;
|
||||
-moz-transform-origin: right bottom;
|
||||
-ms-transform-origin: right bottom;
|
||||
-o-transform-origin: right bottom;
|
||||
transform-origin: right bottom;
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-ms-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.vis.timeline .legend {
|
||||
background-color: rgba(247, 252, 255, 0.65);
|
||||
padding: 5px;
|
||||
border-color: #b3b3b3;
|
||||
border-style:solid;
|
||||
border-width: 1px;
|
||||
box-shadow: 2px 2px 10px rgba(154, 154, 154, 0.55);
|
||||
}
|
||||
|
||||
.vis.timeline .legendText {
|
||||
/*font-size: 10px;*/
|
||||
white-space: nowrap;
|
||||
display: inline-block
|
||||
}
|
||||
.vis.timeline .graphGroup0 {
|
||||
fill:#4f81bd;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #4f81bd;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup1 {
|
||||
fill:#f79646;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #f79646;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup2 {
|
||||
fill: #8c51cf;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #8c51cf;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup3 {
|
||||
fill: #75c841;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #75c841;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup4 {
|
||||
fill: #ff0100;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #ff0100;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup5 {
|
||||
fill: #37d8e6;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #37d8e6;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup6 {
|
||||
fill: #042662;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #042662;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup7 {
|
||||
fill:#00ff26;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #00ff26;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup8 {
|
||||
fill:#ff00ff;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #ff00ff;
|
||||
}
|
||||
|
||||
.vis.timeline .graphGroup9 {
|
||||
fill: #8f3938;
|
||||
fill-opacity:0;
|
||||
stroke-width:2px;
|
||||
stroke: #8f3938;
|
||||
}
|
||||
|
||||
.vis.timeline .fill {
|
||||
fill-opacity:0.1;
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
|
||||
.vis.timeline .bar {
|
||||
fill-opacity:0.5;
|
||||
stroke-width:1px;
|
||||
}
|
||||
|
||||
.vis.timeline .point {
|
||||
stroke-width:2px;
|
||||
fill-opacity:1.0;
|
||||
}
|
||||
|
||||
|
||||
.vis.timeline .legendBackground {
|
||||
stroke-width:1px;
|
||||
fill-opacity:0.9;
|
||||
fill: #ffffff;
|
||||
stroke: #c2c2c2;
|
||||
}
|
||||
|
||||
|
||||
.vis.timeline .outline {
|
||||
stroke-width:1px;
|
||||
fill-opacity:1;
|
||||
fill: #ffffff;
|
||||
stroke: #e5e5e5;
|
||||
}
|
||||
|
||||
.vis.timeline .iconFill {
|
||||
fill-opacity:0.3;
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.network-manipulationDiv {
|
||||
border-width: 0;
|
||||
border-bottom: 1px;
|
||||
border-style:solid;
|
||||
border-color: #d6d9d8;
|
||||
background: #ffffff; /* Old browsers */
|
||||
background: -moz-linear-gradient(top, #ffffff 0%, #fcfcfc 48%, #fafafa 50%, #fcfcfc 100%); /* FF3.6+ */
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#ffffff), color-stop(48%,#fcfcfc), color-stop(50%,#fafafa), color-stop(100%,#fcfcfc)); /* Chrome,Safari4+ */
|
||||
background: -webkit-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Chrome10+,Safari5.1+ */
|
||||
background: -o-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* Opera 11.10+ */
|
||||
background: -ms-linear-gradient(top, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* IE10+ */
|
||||
background: linear-gradient(to bottom, #ffffff 0%,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%); /* W3C */
|
||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#fcfcfc',GradientType=0 ); /* IE6-9 */
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
div.network-manipulation-editMode {
|
||||
position:absolute;
|
||||
left: 0;
|
||||
top: 15px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
div.network-manipulation-closeDiv {
|
||||
position:absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
background-position: 20px 3px;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url("img/network/cross.png");
|
||||
cursor: pointer;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
div.network-manipulation-closeDiv:hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
div.network-manipulationUI {
|
||||
position:relative;
|
||||
top:-7px;
|
||||
font-family: verdana;
|
||||
font-size: 12px;
|
||||
-moz-border-radius: 15px;
|
||||
border-radius: 15px;
|
||||
display:inline-block;
|
||||
background-position: 0px 0px;
|
||||
background-repeat:no-repeat;
|
||||
height:24px;
|
||||
margin: 0px 0px 0px 10px;
|
||||
vertical-align:middle;
|
||||
cursor: pointer;
|
||||
padding: 0px 8px 0px 8px;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
div.network-manipulationUI:hover {
|
||||
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.20);
|
||||
}
|
||||
|
||||
div.network-manipulationUI:active {
|
||||
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.50);
|
||||
}
|
||||
|
||||
div.network-manipulationUI.back {
|
||||
background-image: url("img/network/backIcon.png");
|
||||
}
|
||||
|
||||
div.network-manipulationUI.none:hover {
|
||||
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0);
|
||||
cursor: default;
|
||||
}
|
||||
div.network-manipulationUI.none:active {
|
||||
box-shadow: 1px 1px 8px rgba(0, 0, 0, 0.0);
|
||||
}
|
||||
div.network-manipulationUI.none {
|
||||
padding: 0;
|
||||
}
|
||||
div.network-manipulationUI.notification{
|
||||
margin: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.network-manipulationUI.add {
|
||||
background-image: url("img/network/addNodeIcon.png");
|
||||
}
|
||||
|
||||
div.network-manipulationUI.edit {
|
||||
background-image: url("img/network/editIcon.png");
|
||||
}
|
||||
|
||||
div.network-manipulationUI.edit.editmode {
|
||||
background-color: #fcfcfc;
|
||||
border-style:solid;
|
||||
border-width:1px;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
|
||||
div.network-manipulationUI.connect {
|
||||
background-image: url("img/network/connectIcon.png");
|
||||
}
|
||||
|
||||
div.network-manipulationUI.delete {
|
||||
background-image: url("img/network/deleteIcon.png");
|
||||
}
|
||||
/* top right bottom left */
|
||||
div.network-manipulationLabel {
|
||||
margin: 0px 0px 0px 23px;
|
||||
line-height: 25px;
|
||||
}
|
||||
div.network-seperatorLine {
|
||||
display:inline-block;
|
||||
width:1px;
|
||||
height:20px;
|
||||
background-color: #bdbdbd;
|
||||
margin: 5px 7px 0px 15px;
|
||||
}
|
||||
|
||||
div.network-navigation_wrapper {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
div.network-navigation {
|
||||
width:34px;
|
||||
height:34px;
|
||||
-moz-border-radius: 17px;
|
||||
border-radius: 17px;
|
||||
position:absolute;
|
||||
display:inline-block;
|
||||
background-position: 2px 2px;
|
||||
background-repeat:no-repeat;
|
||||
cursor: pointer;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
div.network-navigation:hover {
|
||||
box-shadow: 0px 0px 3px 3px rgba(56, 207, 21, 0.30);
|
||||
}
|
||||
|
||||
div.network-navigation:active {
|
||||
box-shadow: 0px 0px 1px 3px rgba(56, 207, 21, 0.95);
|
||||
}
|
||||
|
||||
div.network-navigation.up {
|
||||
background-image: url("img/network/upArrow.png");
|
||||
bottom:50px;
|
||||
left:55px;
|
||||
}
|
||||
div.network-navigation.down {
|
||||
background-image: url("img/network/downArrow.png");
|
||||
bottom:10px;
|
||||
left:55px;
|
||||
}
|
||||
div.network-navigation.left {
|
||||
background-image: url("img/network/leftArrow.png");
|
||||
bottom:10px;
|
||||
left:15px;
|
||||
}
|
||||
div.network-navigation.right {
|
||||
background-image: url("img/network/rightArrow.png");
|
||||
bottom:10px;
|
||||
left:95px;
|
||||
}
|
||||
div.network-navigation.zoomIn {
|
||||
background-image: url("img/network/plus.png");
|
||||
bottom:10px;
|
||||
right:15px;
|
||||
}
|
||||
div.network-navigation.zoomOut {
|
||||
background-image: url("img/network/minus.png");
|
||||
bottom:10px;
|
||||
right:55px;
|
||||
}
|
||||
div.network-navigation.zoomExtends {
|
||||
background-image: url("img/network/zoomExtends.png");
|
||||
bottom:50px;
|
||||
right:15px;
|
||||
}
|
||||
div.network-tooltip {
|
||||
position: absolute;
|
||||
visibility: hidden;
|
||||
padding: 5px;
|
||||
white-space: nowrap;
|
||||
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid;
|
||||
|
||||
box-shadow: 3px 3px 10px rgba(128, 128, 128, 0.5);
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -17,7 +17,6 @@
|
|||
<script type="text/javascript" src="./js/jquery.dataTables.min.js"></script>
|
||||
|
||||
<!-- css -->
|
||||
<link type="text/css" href="./css/vis.min.css" rel="stylesheet"/>
|
||||
<link type="text/css" href="./css/monkeys-admin.css" rel="stylesheet"/>
|
||||
<link type="text/css" href="./css/typeahead.css" rel="stylesheet"/>
|
||||
<link type="text/css" href="./css/bootstrap.min.css" rel="stylesheet"/>
|
||||
|
@ -68,14 +67,24 @@
|
|||
<a href="#options" data-toggle="collapse">Options</a>
|
||||
</div>
|
||||
<div id="options" class="panel-body panel-collapse collapse in">
|
||||
<button id="btnCreateJob" class="btn btn-default" type="button"
|
||||
onclick="createNewJob()" style="margin-top:-4px">
|
||||
Create new scenario
|
||||
</button>
|
||||
<span class="input-group-btn">
|
||||
<button id="btnCreateJob" class="btn btn-default" type="button"
|
||||
onclick="createNewJob()" style="margin-top:-4px">
|
||||
Create new scenario
|
||||
</button>
|
||||
<button id="btnConfigSched" class="btn btn-default" type="button"
|
||||
onclick="configSched()" style="margin-top:-4px">
|
||||
Configure Auto Tester
|
||||
</button>
|
||||
</span>
|
||||
<!-- General options -->
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<a href="#general" data-toggle="collapse">General</a>
|
||||
<a href="#newJob" data-toggle="collapse">New Job</a>
|
||||
</div>
|
||||
<div id="newJob" style="overflow: visible" class="panel-body panel-collapse collapse in" aria-expanded="true">
|
||||
<div id="job-config">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.General options -->
|
||||
|
@ -115,8 +124,7 @@
|
|||
Update
|
||||
</button>-->
|
||||
</span>
|
||||
<div style="display: none;" id="job-config">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -96,26 +96,6 @@ function initAdmin() {
|
|||
startval: $,
|
||||
});
|
||||
|
||||
|
||||
jobCfg = new JSONEditor(document.getElementById('job-config'),{
|
||||
schema: {
|
||||
type: "object",
|
||||
title: "Job",
|
||||
properties: {
|
||||
vlan: {
|
||||
title: "Vlan",
|
||||
type: "integer",
|
||||
},
|
||||
},
|
||||
options: {
|
||||
"collapsed": true
|
||||
},
|
||||
},
|
||||
disable_edit_json: false,
|
||||
});
|
||||
|
||||
|
||||
|
||||
window.setTimeout(updateJobs, 10000);
|
||||
loadVcenterConfig();
|
||||
updateJobs();
|
||||
|
@ -141,14 +121,14 @@ function updateJobs() {
|
|||
}
|
||||
|
||||
function loadVcenterConfig() {
|
||||
$.getJSON('/connector?type=vcenter', function(json) {
|
||||
$.getJSON('/connector?type=VCenterConnector', function(json) {
|
||||
vcenterCfg.setValue(json);
|
||||
});
|
||||
}
|
||||
|
||||
function updateVcenterConfig() {
|
||||
var vc_config = vcenterCfg.getValue()
|
||||
vc_config["type"] = "vcenter";
|
||||
vc_config["type"] = "VCenterConnector";
|
||||
|
||||
$.ajax({
|
||||
headers : {
|
||||
|
@ -173,6 +153,30 @@ function updateVcenterConfig() {
|
|||
}
|
||||
|
||||
function createNewJob() {
|
||||
elem = document.getElementById('job-config');
|
||||
elem.innerHTML = ""
|
||||
jobCfg = new JSONEditor(elem,{
|
||||
schema: {
|
||||
type: "object",
|
||||
title: "Job",
|
||||
properties: {
|
||||
job: {
|
||||
title: "Type",
|
||||
$ref: "/jobcreate",
|
||||
}
|
||||
},
|
||||
options: {
|
||||
"collapsed": false
|
||||
},
|
||||
},
|
||||
ajax: true,
|
||||
disable_edit_json: false,
|
||||
disable_collapse: true,
|
||||
disable_properties: true,
|
||||
});
|
||||
}
|
||||
|
||||
function configSched() {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
class NetControllerConnector(object):
|
||||
def __init__(self):
|
||||
_properties = {}
|
||||
self._properties = {}
|
||||
|
||||
def _load_prop_dict(self, target, prop):
|
||||
for property in prop:
|
||||
|
@ -12,6 +12,9 @@ class NetControllerConnector(object):
|
|||
else:
|
||||
target[property] = prop[property]
|
||||
|
||||
def is_connected(self):
|
||||
return False
|
||||
|
||||
def connect(self):
|
||||
return
|
||||
|
||||
|
@ -33,3 +36,19 @@ class NetControllerConnector(object):
|
|||
def disconnect(self):
|
||||
return
|
||||
|
||||
class NetControllerJob(object):
|
||||
connector = NetControllerConnector
|
||||
|
||||
def __init__(self):
|
||||
self._properties = {
|
||||
# property: [value, enumerating_function]
|
||||
}
|
||||
|
||||
def get_job_properties(self):
|
||||
return self._properties
|
||||
|
||||
def set_job_properties(self, properties):
|
||||
return {}
|
||||
|
||||
def run(self):
|
||||
raise NotImplementedError()
|
|
@ -0,0 +1,43 @@
|
|||
from connectors import NetControllerJob, NetControllerConnector
|
||||
|
||||
demo_state = {
|
||||
501: ["Machine A", "Machine B"],
|
||||
502: ["Machine C",],
|
||||
503: ["Machine D",],
|
||||
514: ["Machine E", "Machine F"],
|
||||
}
|
||||
|
||||
class DemoConnector(NetControllerConnector):
|
||||
def __init__(self):
|
||||
self._conn = None
|
||||
self._properties = {
|
||||
"address": "127.0.0.1",
|
||||
"port": 0,
|
||||
"username": "",
|
||||
"password": "",
|
||||
}
|
||||
|
||||
def connect(self):
|
||||
self._conn = object()
|
||||
|
||||
def is_connected(self):
|
||||
return not self._conn == None
|
||||
|
||||
def disconnect(self):
|
||||
self._conn = None
|
||||
|
||||
def get_vlans_list(self):
|
||||
return demo_state.keys()
|
||||
|
||||
def get_entities_on_vlan(self, vlanid):
|
||||
if (demo_state.has_key(vlanid)):
|
||||
return demo_state[vlanid]
|
||||
return []
|
||||
|
||||
class DemoJob(NetControllerJob):
|
||||
connector = DemoConnector
|
||||
|
||||
def __init__(self):
|
||||
self._properties = {
|
||||
"vlan": [0, "get_vlans_list"],
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
from connectors import NetControllerConnector
|
||||
from connectors import NetControllerJob, NetControllerConnector
|
||||
from pyVmomi import vim
|
||||
from pyVim.connect import SmartConnect, Disconnect
|
||||
|
||||
|
||||
class VCenterConnector(NetControllerConnector):
|
||||
def __init__(self):
|
||||
self._service_instance = None
|
||||
|
@ -21,15 +20,45 @@ class VCenterConnector(NetControllerConnector):
|
|||
"resource_pool": ""
|
||||
}
|
||||
}
|
||||
self._cache = {
|
||||
"vlans" : []
|
||||
}
|
||||
|
||||
def connect(self):
|
||||
self._service_instance = SmartConnect(host=self._address,
|
||||
port=self._port,
|
||||
user=self._username,
|
||||
pwd=self._password)
|
||||
import ssl
|
||||
try:
|
||||
self._service_instance = SmartConnect(host=self._properties["address"],
|
||||
port=self._properties["port"],
|
||||
user=self._properties["username"],
|
||||
pwd=self._properties["password"])
|
||||
except ssl.SSLError:
|
||||
# some organizations use self-signed certificates...
|
||||
gcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
||||
self._service_instance = SmartConnect(host=self._properties["address"],
|
||||
port=self._properties["port"],
|
||||
user=self._properties["username"],
|
||||
pwd=self._properties["password"],
|
||||
sslContext=gcontext)
|
||||
|
||||
def is_connected(self):
|
||||
if (self._service_instance == None):
|
||||
return False
|
||||
try:
|
||||
self._service_instance.serverClock
|
||||
except vim.fault.NotAuthenticated, e:
|
||||
return False
|
||||
|
||||
def get_vlans_list(self):
|
||||
return []
|
||||
if not self.is_connected():
|
||||
self.connect()
|
||||
if self._cache and self._cache.has_key("vlans") and self._cache["vlans"]:
|
||||
return self._cache["vlans"]
|
||||
vcontent = self._service_instance.RetrieveContent() # get updated vsphare state
|
||||
vimtype = [vim.Network]
|
||||
objview = vcontent.viewManager.CreateContainerView(vcontent.rootFolder, vimtype, True)
|
||||
self._cache["vlans"] = [x.name for x in objview.view]
|
||||
objview.Destroy()
|
||||
return self._cache["vlans"]
|
||||
|
||||
def get_entities_on_vlan(self, vlanid):
|
||||
return []
|
||||
|
@ -120,4 +149,14 @@ class VCenterConnector(NetControllerConnector):
|
|||
obj = c
|
||||
break
|
||||
|
||||
return obj
|
||||
return obj
|
||||
|
||||
|
||||
class VCenterJob(NetControllerJob):
|
||||
connector = VCenterConnector
|
||||
|
||||
def __init__(self):
|
||||
self._properties = {
|
||||
"vlan": [0, "get_vlans_list"],
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import os
|
||||
import sys
|
||||
from flask import Flask, request, abort, send_from_directory
|
||||
from flask.ext import restful
|
||||
from flask.ext.pymongo import PyMongo
|
||||
|
@ -7,7 +8,8 @@ import bson.json_util
|
|||
import json
|
||||
from datetime import datetime
|
||||
import dateutil.parser
|
||||
from connectors.vcenter import VCenterConnector
|
||||
from connectors.vcenter import VCenterJob, VCenterConnector
|
||||
from connectors.demo import DemoJob, DemoConnector
|
||||
|
||||
MONGO_URL = os.environ.get('MONGO_URL')
|
||||
if not MONGO_URL:
|
||||
|
@ -17,6 +19,10 @@ app = Flask(__name__)
|
|||
app.config['MONGO_URI'] = MONGO_URL
|
||||
mongo = PyMongo(app)
|
||||
|
||||
available_jobs = [VCenterJob, DemoJob]
|
||||
|
||||
active_connectors = {}
|
||||
|
||||
class Root(restful.Resource):
|
||||
def get(self):
|
||||
return {
|
||||
|
@ -64,9 +70,9 @@ class Job(restful.Resource):
|
|||
class Connector(restful.Resource):
|
||||
def get(self, **kw):
|
||||
type = request.args.get('type')
|
||||
if (type == 'vcenter'):
|
||||
if (type == 'VCenterConnector'):
|
||||
vcenter = VCenterConnector()
|
||||
properties = mongo.db.connector.find_one({"type": 'vcenter'})
|
||||
properties = mongo.db.connector.find_one({"type": 'VCenterConnector'})
|
||||
if properties:
|
||||
vcenter.load_properties(properties)
|
||||
ret = vcenter.get_properties()
|
||||
|
@ -76,17 +82,61 @@ class Connector(restful.Resource):
|
|||
|
||||
def post(self, **kw):
|
||||
settings_json = json.loads(request.data)
|
||||
if (settings_json.get("type") == 'vcenter'):
|
||||
if (settings_json.get("type") == 'VCenterConnector'):
|
||||
|
||||
# preserve password
|
||||
properties = mongo.db.connector.find_one({"type": 'vcenter'})
|
||||
properties = mongo.db.connector.find_one({"type": 'VCenterConnector'})
|
||||
if properties and (not settings_json.has_key("password") or not settings_json["password"]):
|
||||
settings_json["password"] = properties.get("password")
|
||||
|
||||
return mongo.db.connector.update({"type": 'vcenter'},
|
||||
return mongo.db.connector.update({"type": 'VCenterConnector'},
|
||||
{"$set": settings_json},
|
||||
upsert=True)
|
||||
|
||||
class JobCreation(restful.Resource):
|
||||
def get(self, **kw):
|
||||
jobtype = request.args.get('type')
|
||||
if not jobtype:
|
||||
res = []
|
||||
update_connectors()
|
||||
for con in available_jobs:
|
||||
if con.connector.__name__ in active_connectors:
|
||||
res.append({"title": con.__name__, "$ref": "/jobcreate?type=" + con.__name__})
|
||||
return {"oneOf": res}
|
||||
|
||||
job = None
|
||||
for jobclass in available_jobs:
|
||||
if jobclass.__name__ == jobtype:
|
||||
job = jobclass()
|
||||
|
||||
if job and job.connector.__name__ in active_connectors.keys():
|
||||
properties = dict()
|
||||
job_prop = job.get_job_properties()
|
||||
|
||||
for prop in job_prop:
|
||||
properties[prop] = dict({})
|
||||
if type(job_prop[prop][0]) is int:
|
||||
properties[prop]["type"] = "number"
|
||||
elif type(job_prop[prop][0]) is bool:
|
||||
properties[prop]["type"] = "boolean"
|
||||
else:
|
||||
properties[prop]["type"] = "string"
|
||||
if job_prop[prop][1]:
|
||||
properties[prop]["enum"] = list(active_connectors[job.connector.__name__].__getattribute__(job_prop[prop][1])())
|
||||
|
||||
res = dict({
|
||||
"title": "%s Job" % jobtype,
|
||||
"type": "object",
|
||||
"options": {
|
||||
"disable_collapse": True,
|
||||
"disable_properties": True,
|
||||
},
|
||||
"properties": properties
|
||||
})
|
||||
return res
|
||||
|
||||
return {}
|
||||
|
||||
|
||||
def normalize_obj(obj):
|
||||
if obj.has_key('_id') and not obj.has_key('id'):
|
||||
|
@ -113,6 +163,30 @@ def output_json(obj, code, headers=None):
|
|||
resp.headers.extend(headers or {})
|
||||
return resp
|
||||
|
||||
|
||||
def refresh_connector_config(name):
|
||||
properties = mongo.db.connector.find_one({"type": name})
|
||||
if properties:
|
||||
active_connectors[name].load_properties(properties)
|
||||
|
||||
|
||||
def update_connectors():
|
||||
for con in available_jobs:
|
||||
connector_name = con.connector.__name__
|
||||
if connector_name not in active_connectors:
|
||||
active_connectors[connector_name] = con.connector()
|
||||
|
||||
if not active_connectors[connector_name].is_connected():
|
||||
refresh_connector_config(connector_name)
|
||||
try:
|
||||
app.logger.info("Trying to activate connector: %s" % connector_name)
|
||||
active_connectors[connector_name].connect()
|
||||
except Exception, e:
|
||||
active_connectors.pop(connector_name)
|
||||
app.logger.info("Error activating connector: %s, reason: %s" % (connector_name, e))
|
||||
|
||||
|
||||
|
||||
@app.route('/admin/<path:path>')
|
||||
def send_admin(path):
|
||||
return send_from_directory('admin/ui', path)
|
||||
|
@ -124,6 +198,7 @@ api.representations = DEFAULT_REPRESENTATIONS
|
|||
api.add_resource(Root, '/api')
|
||||
api.add_resource(Job, '/job')
|
||||
api.add_resource(Connector, '/connector')
|
||||
api.add_resource(JobCreation, '/jobcreate')
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', debug=True, ssl_context=('server.crt', 'server.key'))
|
||||
|
|
Loading…
Reference in New Issue