Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
bacb4843
Commit
bacb4843
authored
Dec 31, 2013
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
removed a lot of filterSrv functionality
parent
e1daa502
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
52 additions
and
246 deletions
+52
-246
src/app/controllers/dash.js
+1
-7
src/app/controllers/dashLoader.js
+2
-7
src/app/controllers/graphiteTarget.js
+1
-0
src/app/panels/filtering/module.html
+11
-7
src/app/panels/filtering/module.js
+5
-6
src/app/panels/graphite/module.js
+2
-4
src/app/panels/histogram/module.js
+2
-2
src/app/panels/timepicker/module.html
+2
-2
src/app/panels/timepicker/module.js
+4
-22
src/app/partials/dashboard.html
+1
-2
src/app/services/filterSrv.js
+16
-187
src/css/bootstrap.dark.min.css
+0
-0
src/vendor/bootstrap/less/grafana.less
+5
-0
No files found.
src/app/controllers/dash.js
View file @
bacb4843
...
...
@@ -80,7 +80,7 @@ function (angular, $, config, _) {
keyboardManager
.
bind
(
'ctrl+h'
,
function
()
{
var
current
=
dashboard
.
current
.
hideControls
;
dashboard
.
current
.
hideControls
=
!
current
;
dashboard
.
current
.
panel_hints
=
!
current
;
dashboard
.
current
.
panel_hints
=
current
;
},
{
inputDisabled
:
true
});
keyboardManager
.
bind
(
'ctrl+s'
,
function
(
evt
)
{
...
...
@@ -162,12 +162,6 @@ function (angular, $, config, _) {
}
};
$scope
.
pulldownTabStyle
=
function
(
i
)
{
var
classes
=
[
'bgPrimary'
,
'bgSuccess'
,
'bgWarning'
,
'bgDanger'
,
'bgInverse'
,
'bgInfo'
];
i
=
i
%
classes
.
length
;
return
classes
[
i
];
};
$scope
.
setEditorTabs
=
function
(
panelMeta
)
{
$scope
.
editorTabs
=
[
'General'
,
'Panel'
];
if
(
!
_
.
isUndefined
(
panelMeta
.
editorTabs
))
{
...
...
src/app/controllers/dashLoader.js
View file @
bacb4843
...
...
@@ -139,7 +139,7 @@ function (angular, _, moment) {
// function $scope.zoom
// factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan
$scope
.
zoom
=
function
(
factor
)
{
var
_range
=
filterSrv
.
timeRange
(
'last'
);
var
_range
=
filterSrv
.
timeRange
();
var
_timespan
=
(
_range
.
to
.
valueOf
()
-
_range
.
from
.
valueOf
());
var
_center
=
_range
.
to
.
valueOf
()
-
_timespan
/
2
;
...
...
@@ -153,12 +153,7 @@ function (angular, _, moment) {
_to
=
Date
.
now
();
}
if
(
factor
>
1
)
{
filterSrv
.
removeByType
(
'time'
);
}
filterSrv
.
set
({
type
:
'time'
,
filterSrv
.
setTime
({
from
:
moment
.
utc
(
_from
).
toDate
(),
to
:
moment
.
utc
(
_to
).
toDate
(),
});
...
...
src/app/controllers/graphiteTarget.js
View file @
bacb4843
...
...
@@ -28,6 +28,7 @@ function (angular, _, config, graphiteFuncs, Parser) {
var
astNode
=
parser
.
getAst
();
if
(
astNode
===
null
)
{
checkOtherSegments
(
0
);
return
;
}
if
(
astNode
.
type
===
'error'
)
{
...
...
src/app/panels/filtering/module.html
View file @
bacb4843
<div
ng-controller=
'filtering'
ng-init=
"init()"
>
<style>
.filtering-container
{
margin-top
:
3px
;
float
:
left
;
}
.filter-panel-filter
{
display
:
inline-block
;
vertical-align
:
top
;
width
:
220px
;
padding
:
5px
5px
0px
5px
;
margin
:
5px
5px
5px
0px
;
color
:
#fff
;
margin
:
0px
5px
;
background-color
:
#444
;
}
.filter-panel-filter
ul
{
...
...
@@ -23,6 +22,11 @@
float
:
right
;
margin-bottom
:
0px
!important
;
margin-left
:
3px
;
margin-top
:
3px
;
}
.add-filter-action
{
position
:
relative
;
top
:
3px
;
}
.filter-mandate
{
text-decoration
:
underline
;
...
...
@@ -37,10 +41,9 @@
<span
ng-show=
"filterSrv.ids.length == 0"
>
<h5>
No filters available
</h5>
</span>
<div
ng-repeat=
"id in filterSrv.ids"
class=
"small filter-panel-filter"
>
<div
ng-repeat=
"id in filterSrv.ids"
ng-show=
"filterSrv.list[id].type !== 'time'"
class=
"small filter-panel-filter"
>
<div>
<i
class=
"filter-action pointer icon-remove"
bs-tooltip=
"'Remove'"
ng-click=
"remove(id)"
></i>
<i
class=
"filter-action pointer"
ng-class=
"{'icon-check': filterSrv.list[id].active,'icon-check-empty': !filterSrv.list[id].active}"
bs-tooltip=
"'Toggle'"
ng-click=
"toggle(id)"
></i>
<i
class=
"filter-action pointer icon-edit"
ng-hide=
"filterSrv.list[id].editing || !isEditable(filterSrv.list[id])"
bs-tooltip=
"'Edit'"
ng-click=
"filterSrv.list[id].editing = true"
></i>
</div>
...
...
@@ -65,12 +68,12 @@
</li>
</ul>
<div>
<input
type=
"submit"
value=
"Apply"
ng-click=
"
filterSrv.list[id].editing=undefined;refresh(
)"
class=
"filter-apply btn btn-success btn-mini"
bs-tooltip=
"'Save and refresh'"
/>
<input
type=
"submit"
value=
"Apply"
ng-click=
"
applyFilter(filterSrv.list[id]
)"
class=
"filter-apply btn btn-success btn-mini"
bs-tooltip=
"'Save and refresh'"
/>
<button
ng-click=
"filterSrv.list[id].editing=undefined"
class=
"filter-apply btn btn-mini"
bs-tooltip=
"'Save without refresh'"
>
Save
</button>
</div>
</form>
</div>
<i
class=
"pointer icon-plus-sign"
ng-click=
"add()"
bs-tooltip=
"'Add metric filter / param'"
data-placement=
"right"
></i>
<i
class=
"pointer icon-plus-sign
add-filter-action
"
ng-click=
"add()"
bs-tooltip=
"'Add metric filter / param'"
data-placement=
"right"
></i>
</div>
</div>
\ No newline at end of file
src/app/panels/filtering/module.js
View file @
bacb4843
...
...
@@ -34,14 +34,13 @@ function (angular, app, _) {
$scope
.
filterSrv
=
filterSrv
;
};
$scope
.
remove
=
function
(
id
)
{
filterSrv
.
remove
(
id
);
$scope
.
remove
=
function
(
filter
)
{
filterSrv
.
remove
(
filter
);
};
// This function should be moved to the service
$scope
.
toggle
=
function
(
id
)
{
filterSrv
.
list
[
id
].
active
=
!
filterSrv
.
list
[
id
].
active
;
dashboard
.
refresh
();
$scope
.
applyFilter
=
function
(
filter
)
{
filterSrv
.
list
[
id
].
editing
=
undefined
;
$scope
.
refresh
()
};
$scope
.
add
=
function
()
{
...
...
src/app/panels/graphite/module.js
View file @
bacb4843
...
...
@@ -262,7 +262,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
* @return {[type]} [description]
*/
$scope
.
get_time_range
=
function
()
{
var
range
=
$scope
.
range
=
filterSrv
.
timeRange
(
'last'
);
var
range
=
$scope
.
range
=
filterSrv
.
timeRange
();
return
range
;
};
...
...
@@ -354,7 +354,6 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
var
target
=
graphiteSrv
.
match
(
$scope
.
panel
.
targets
,
targetData
.
target
);
var
alias
=
targetData
.
target
;
var
color
=
$scope
.
panel
.
aliasColors
[
alias
]
||
$scope
.
colors
[
data
.
length
];
var
seriesInfo
=
{
alias
:
alias
,
color
:
color
,
...
...
@@ -733,8 +732,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
});
elem
.
bind
(
"plotselected"
,
function
(
event
,
ranges
)
{
filterSrv
.
set
({
type
:
'time'
,
filterSrv
.
setTime
({
from
:
moment
.
utc
(
ranges
.
xaxis
.
from
).
toDate
(),
to
:
moment
.
utc
(
ranges
.
xaxis
.
to
).
toDate
(),
});
...
...
src/app/panels/histogram/module.js
View file @
bacb4843
...
...
@@ -269,7 +269,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
* @return {[type]} [description]
*/
$scope
.
get_time_range
=
function
()
{
var
range
=
$scope
.
range
=
filterSrv
.
timeRange
(
'last'
);
var
range
=
$scope
.
range
=
filterSrv
.
timeRange
();
return
range
;
};
...
...
@@ -475,7 +475,7 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
// function $scope.zoom
// factor :: Zoom factor, so 0.5 = cuts timespan in half, 2 doubles timespan
$scope
.
zoom
=
function
(
factor
)
{
var
_range
=
filterSrv
.
timeRange
(
'last'
);
var
_range
=
filterSrv
.
timeRange
();
var
_timespan
=
(
_range
.
to
.
valueOf
()
-
_range
.
from
.
valueOf
());
var
_center
=
_range
.
to
.
valueOf
()
-
_timespan
/
2
;
...
...
src/app/panels/timepicker/module.html
View file @
bacb4843
...
...
@@ -17,14 +17,14 @@
<a
class=
"dropdown-toggle timepicker-dropdown"
data-toggle=
"dropdown"
href=
""
bs-tooltip=
"time.from.date ? (time.from.date | date:'yyyy-MM-dd HH:mm:ss.sss') + ' <br>to<br>' +(time.to.date | date:'yyyy-MM-dd HH:mm:ss.sss') : 'Click to set a time filter'"
data-placement=
"bottom"
ng-click=
"dismiss();"
>
<span
ng-show=
"filterSrv.
idsByType('time').length
"
>
<span
ng-show=
"filterSrv.
time
"
>
<span
class=
"pointer"
ng-hide=
"panel.now"
>
{{time.from.date | date:'MMM d, y HH:mm:ss'}}
</span>
<span
class=
"pointer"
ng-show=
"panel.now"
>
{{time.from.date | moment:'ago'}}
</span>
to
<span
class=
"pointer"
ng-hide=
"panel.now"
>
{{time.to.date | date:'MMM d, y HH:mm:ss'}}
</span>
<span
class=
"pointer"
ng-show=
"panel.now"
>
{{time.to.date | moment:'ago'}}
</span>
</span>
<span
ng-hide=
"filterSrv.
idsByType('time').length
"
>
Time filter
</span>
<span
ng-hide=
"filterSrv.
time
"
>
Time filter
</span>
<span
ng-show=
"dashboard.current.refresh"
class=
"text-warning"
>
refreshed every {{dashboard.current.refresh}}
</span>
<i
class=
"icon-caret-down"
></i>
</a>
...
...
src/app/panels/timepicker/module.js
View file @
bacb4843
...
...
@@ -65,7 +65,7 @@ function (angular, app, _, moment, kbn) {
$scope
.
$on
(
'refresh'
,
function
(){
$scope
.
init
();});
$scope
.
init
=
function
()
{
var
time
=
filterSrv
.
timeRange
(
'last'
);
var
time
=
filterSrv
.
timeRange
();
if
(
time
)
{
$scope
.
panel
.
now
=
filterSrv
.
timeRange
(
false
).
to
===
"now"
?
true
:
false
;
$scope
.
time
=
getScopeTimeObj
(
time
.
from
,
time
.
to
);
...
...
@@ -124,49 +124,31 @@ function (angular, app, _, moment, kbn) {
}
*/
$scope
.
setAbsoluteTimeFilter
=
function
(
time
)
{
// Create filter object
var
_filter
=
_
.
clone
(
time
);
_filter
.
type
=
'time'
;
_filter
.
field
=
$scope
.
panel
.
timefield
;
if
(
$scope
.
panel
.
now
)
{
_filter
.
to
=
"now"
;
}
// Clear all time filters, set a new one
filterSrv
.
removeByType
(
'time'
,
true
);
// Set the filter
$scope
.
panel
.
filter_id
=
filterSrv
.
set
(
_filter
);
$scope
.
panel
.
filter_id
=
filterSrv
.
set
Time
(
_filter
);
// Update our representation
$scope
.
time
=
getScopeTimeObj
(
time
.
from
,
time
.
to
);
return
$scope
.
panel
.
filter_id
;
};
$scope
.
setRelativeFilter
=
function
(
timespan
)
{
$scope
.
panel
.
now
=
true
;
// Create filter object
var
_filter
=
{
type
:
'time'
,
from
:
"now-"
+
timespan
,
to
:
"now"
};
// Clear all time filters, set a new one
filterSrv
.
removeByType
(
'time'
,
true
);
// Set the filter
$scope
.
panel
.
filter_id
=
filterSrv
.
set
(
_filter
);
filterSrv
.
setTime
(
_filter
);
// Update our representation
$scope
.
time
=
getScopeTimeObj
(
kbn
.
parseDate
(
_filter
.
from
),
new
Date
());
return
$scope
.
panel
.
filter_id
;
};
var
pad
=
function
(
n
,
width
,
z
)
{
...
...
src/app/partials/dashboard.html
View file @
bacb4843
<!-- is there a better way to repeat without actually affecting the page? -->
<nil
ng-repeat=
"pulldown in dashboard.current.pulldowns"
ng-controller=
"PulldownCtrl"
ng-show=
"pulldown.enable"
>
<div
class=
"top-row-close pointer pull-left"
ng-cl
ass=
"pulldownTabStyle($index)"
ng-cl
ick=
"toggle_pulldown(pulldown);dismiss();"
bs-tooltip=
"'Toggle '+pulldown.type"
data-placement=
"bottom"
>
<div
class=
"top-row-close pointer pull-left"
ng-click=
"toggle_pulldown(pulldown);dismiss();"
bs-tooltip=
"'Toggle '+pulldown.type"
data-placement=
"bottom"
>
<span
class=
"small"
>
{{pulldown.type}}
</span>
<i
class=
"small"
ng-class=
"{'icon-caret-left':pulldown.collapse,'icon-caret-right':!pulldown.collapse}"
></i>
<i
class=
"small icon-star"
ng-show=
"row.notice && pulldown.collapse"
></i>
</div>
<div
class=
"clearfix bgNav"
ng-hide=
"pulldown.collapse"
></div>
<div
class=
"top-row-open"
ng-hide=
"pulldown.collapse"
>
<kibana-simple-panel
type=
"pulldown.type"
ng-cloak
></kibana-simple-panel>
</div>
...
...
src/app/services/filterSrv.js
View file @
bacb4843
...
...
@@ -8,210 +8,53 @@ define([
var
module
=
angular
.
module
(
'kibana.services'
);
module
.
service
(
'filterSrv'
,
function
(
dashboard
,
ejsResource
,
$rootScope
,
$timeout
)
{
module
.
service
(
'filterSrv'
,
function
(
dashboard
,
$rootScope
,
$timeout
)
{
// Create an object to hold our service state on the dashboard
dashboard
.
current
.
services
.
filter
=
dashboard
.
current
.
services
.
filter
||
{};
//
Defaults for it
//
defaults
var
_d
=
{
list
:
{}
,
ids
:
[]
list
:
[]
,
time
:
{}
};
// For convenience
var
ejs
=
ejsResource
(
config
.
elasticsearch
);
// Save a reference to this
var
self
=
this
;
// Call this whenever we need to reload the important stuff
this
.
init
=
function
()
{
// Populate defaults
_
.
defaults
(
dashboard
.
current
.
services
.
filter
,
_d
);
// Accessors
_
.
defaults
(
dashboard
.
current
.
services
.
filter
,
_d
);
self
.
list
=
dashboard
.
current
.
services
.
filter
.
list
;
self
.
ids
=
dashboard
.
current
.
services
.
filter
.
ids
;
_
.
each
(
self
.
list
,
function
(
f
)
{
self
.
set
(
f
,
f
.
id
,
true
);
});
// Date filters hold strings now, not dates
/*
_.each(self.getByType('time',true),function(time) {
self.list[time.id].from = new Date(time.from);
self.list[time.id].to = new Date(time.to);
});
*/
self
.
time
=
dashboard
.
current
.
services
.
filter
.
time
;
};
// This is used both for adding filters and modifying them.
// If an id is passed, the filter at that id is updated
this
.
set
=
function
(
filter
,
id
,
noRefresh
)
{
var
_r
;
_
.
defaults
(
filter
,{
active
:
true
});
this
.
add
=
function
(
filter
)
{
self
.
list
.
add
(
filter
);
};
if
(
!
id
&&
filter
.
type
===
'time'
)
{
var
_existing
=
_
.
findWhere
(
self
.
list
,
{
type
:
'time'
});
if
(
_existing
)
{
id
=
_existing
.
id
;
}
}
this
.
remove
=
function
(
filter
)
{
self
.
list
=
dashboard
.
current
.
services
.
filters
=
_
.
without
(
self
.
list
,
filter
);
if
(
!
_
.
isUndefined
(
id
))
{
if
(
!
_
.
isUndefined
(
self
.
list
[
id
]))
{
_
.
extend
(
self
.
list
[
id
],
filter
);
_r
=
id
;
}
else
{
_r
=
false
;
}
}
else
{
if
(
_
.
isUndefined
(
filter
.
type
))
{
_r
=
false
;
}
else
{
var
_id
=
nextId
();
var
_filter
=
{
id
:
_id
,
};
_
.
defaults
(
filter
,
_filter
);
self
.
list
[
_id
]
=
filter
;
self
.
ids
.
push
(
_id
);
_r
=
_id
;
}
}
if
(
!
$rootScope
.
$$phase
)
{
$rootScope
.
$apply
();
}
if
(
noRefresh
!==
true
)
{
$timeout
(
function
(){
dashboard
.
refresh
();
},
0
);
}
$rootScope
.
$broadcast
(
'filter'
);
return
_r
;
};
this
.
remove
=
function
(
id
,
noRefresh
)
{
var
_r
;
if
(
!
_
.
isUndefined
(
self
.
list
[
id
]))
{
delete
self
.
list
[
id
];
// This must happen on the full path also since _.without returns a copy
self
.
ids
=
dashboard
.
current
.
services
.
filter
.
ids
=
_
.
without
(
self
.
ids
,
id
);
_r
=
true
;
}
else
{
_r
=
false
;
}
if
(
!
$rootScope
.
$$phase
)
{
$rootScope
.
$apply
();
}
if
(
noRefresh
!==
true
)
{
$timeout
(
function
(){
dashboard
.
refresh
();
},
0
);
}
$rootScope
.
$broadcast
(
'filter'
);
return
_r
;
};
this
.
removeByType
=
function
(
type
,
noRefresh
)
{
var
ids
=
self
.
idsByType
(
type
);
_
.
each
(
ids
,
function
(
id
)
{
self
.
remove
(
id
,
true
);
});
if
(
noRefresh
!==
true
)
{
this
.
setTime
=
function
(
time
)
{
_
.
extend
(
self
.
time
,
time
);
$timeout
(
function
(){
dashboard
.
refresh
();
},
0
);
}
return
ids
;
};
this
.
getBoolFilter
=
function
(
ids
)
{
var
bool
=
ejs
.
BoolFilter
();
// there is no way to introspect the BoolFilter and find out if it has a filter. We must keep note.
var
added_a_filter
=
false
;
_
.
each
(
ids
,
function
(
id
)
{
if
(
self
.
list
[
id
].
active
)
{
added_a_filter
=
true
;
switch
(
self
.
list
[
id
].
mandate
)
{
case
'mustNot'
:
bool
.
mustNot
(
self
.
getEjsObj
(
id
));
break
;
case
'either'
:
bool
.
should
(
self
.
getEjsObj
(
id
));
break
;
default
:
bool
.
must
(
self
.
getEjsObj
(
id
));
}
}
});
// add a match filter so we'd get some data
if
(
!
added_a_filter
)
{
bool
.
must
(
ejs
.
MatchAllFilter
());
}
return
bool
;
};
this
.
getEjsObj
=
function
(
id
)
{
return
self
.
toEjsObj
(
self
.
list
[
id
]);
};
this
.
toEjsObj
=
function
(
filter
)
{
if
(
!
filter
.
active
)
{
return
false
;
}
switch
(
filter
.
type
)
{
case
'time'
:
var
_f
=
ejs
.
RangeFilter
(
filter
.
field
).
from
(
kbn
.
parseDate
(
filter
.
from
).
valueOf
());
if
(
!
_
.
isUndefined
(
filter
.
to
))
{
_f
=
_f
.
to
(
filter
.
to
.
valueOf
());
}
return
_f
;
case
'range'
:
return
ejs
.
RangeFilter
(
filter
.
field
)
.
from
(
filter
.
from
)
.
to
(
filter
.
to
);
case
'querystring'
:
return
ejs
.
QueryFilter
(
ejs
.
QueryStringQuery
(
filter
.
query
)).
cache
(
true
);
case
'field'
:
return
ejs
.
QueryFilter
(
ejs
.
FieldQuery
(
filter
.
field
,
filter
.
query
)).
cache
(
true
);
case
'terms'
:
return
ejs
.
TermsFilter
(
filter
.
field
,
filter
.
value
);
case
'exists'
:
return
ejs
.
ExistsFilter
(
filter
.
field
);
case
'missing'
:
return
ejs
.
MissingFilter
(
filter
.
field
);
default
:
return
false
;
}
};
this
.
getByType
=
function
(
type
,
inactive
)
{
return
_
.
pick
(
self
.
list
,
self
.
idsByType
(
type
,
inactive
));
};
this
.
idsByType
=
function
(
type
,
inactive
)
{
var
_require
=
inactive
?
{
type
:
type
}
:
{
type
:
type
,
active
:
true
};
return
_
.
pluck
(
_
.
where
(
self
.
list
,
_require
),
'id'
);
};
// TOFIX: Error handling when there is more than one field
this
.
timeField
=
function
()
{
return
_
.
pluck
(
self
.
getByType
(
'time'
),
'field'
);
};
// Parse is used when you need to know about the raw filter
this
.
timeRange
=
function
(
parse
)
{
var
_t
=
_
.
last
(
_
.
where
(
self
.
list
,{
type
:
'time'
,
active
:
true
}));
var
_t
=
self
.
time
;
if
(
_
.
isUndefined
(
_t
))
{
return
false
;
}
...
...
@@ -232,20 +75,6 @@ define([
}
};
var
nextId
=
function
()
{
var
idCount
=
dashboard
.
current
.
services
.
filter
.
ids
.
length
;
if
(
idCount
>
0
)
{
// Make a sorted copy of the ids array
var
ids
=
_
.
sortBy
(
_
.
clone
(
dashboard
.
current
.
services
.
filter
.
ids
),
function
(
num
){
return
num
;
});
return
kbn
.
smallestMissing
(
ids
);
}
else
{
// No ids currently in list
return
0
;
}
};
// Now init
self
.
init
();
});
...
...
src/css/bootstrap.dark.min.css
View file @
bacb4843
This source diff could not be displayed because it is too large. You can
view the blob
instead.
src/vendor/bootstrap/less/grafana.less
View file @
bacb4843
...
...
@@ -30,6 +30,11 @@
}
}
.top-row-open {
float: left;
padding: 0 10px;
}
.panelCont {
padding: 0px 10px;
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment