Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
fc7fab87
Commit
fc7fab87
authored
Aug 08, 2019
by
GitLab Bot
Browse files
Options
Browse Files
Download
Plain Diff
Automatic merge of gitlab-org/gitlab-ce master
parents
339015e2
c5495b52
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
141 additions
and
72 deletions
+141
-72
app/assets/javascripts/lib/utils/url_utility.js
app/assets/javascripts/lib/utils/url_utility.js
+2
-2
app/assets/javascripts/monitoring/components/dashboard.vue
app/assets/javascripts/monitoring/components/dashboard.vue
+19
-15
app/assets/javascripts/monitoring/components/embed.vue
app/assets/javascripts/monitoring/components/embed.vue
+13
-5
app/assets/javascripts/monitoring/constants.js
app/assets/javascripts/monitoring/constants.js
+15
-7
app/assets/javascripts/monitoring/stores/actions.js
app/assets/javascripts/monitoring/stores/actions.js
+1
-1
app/assets/javascripts/monitoring/utils.js
app/assets/javascripts/monitoring/utils.js
+17
-28
changelogs/unreleased/62973-specify-time-frame-in-shareable-link-for-embedding-metrics.yml
...fy-time-frame-in-shareable-link-for-embedding-metrics.yml
+5
-0
spec/frontend/lib/utils/url_utility_spec.js
spec/frontend/lib/utils/url_utility_spec.js
+35
-0
spec/javascripts/monitoring/dashboard_spec.js
spec/javascripts/monitoring/dashboard_spec.js
+13
-3
spec/javascripts/monitoring/store/actions_spec.js
spec/javascripts/monitoring/store/actions_spec.js
+2
-2
spec/javascripts/monitoring/utils_spec.js
spec/javascripts/monitoring/utils_spec.js
+19
-9
No files found.
app/assets/javascripts/lib/utils/url_utility.js
View file @
fc7fab87
...
...
@@ -2,8 +2,8 @@ import { join as joinPaths } from 'path';
// Returns an array containing the value(s) of the
// of the key passed as an argument
export
function
getParameterValues
(
sParam
)
{
const
sPageURL
=
decodeURIComponent
(
window
.
location
.
search
.
substring
(
1
));
export
function
getParameterValues
(
sParam
,
url
=
window
.
location
)
{
const
sPageURL
=
decodeURIComponent
(
new
URL
(
url
)
.
search
.
substring
(
1
));
return
sPageURL
.
split
(
'
&
'
).
reduce
((
acc
,
urlParam
)
=>
{
const
sParameterName
=
urlParam
.
split
(
'
=
'
);
...
...
app/assets/javascripts/monitoring/components/dashboard.vue
View file @
fc7fab87
...
...
@@ -18,8 +18,8 @@ import MonitorSingleStatChart from './charts/single_stat.vue';
import
PanelType
from
'
./panel_type.vue
'
;
import
GraphGroup
from
'
./graph_group.vue
'
;
import
EmptyState
from
'
./empty_state.vue
'
;
import
{
sidebarAnimationDuration
,
timeWindows
,
timeWindowsKeyNames
}
from
'
../constants
'
;
import
{
getTimeDiff
}
from
'
../utils
'
;
import
{
sidebarAnimationDuration
,
timeWindows
}
from
'
../constants
'
;
import
{
getTimeDiff
,
getTimeWindow
}
from
'
../utils
'
;
let
sidebarMutationObserver
;
...
...
@@ -147,6 +147,7 @@ export default {
selectedTimeWindow
:
''
,
selectedTimeWindowKey
:
''
,
formIsValid
:
null
,
timeWindows
:
{},
};
},
computed
:
{
...
...
@@ -184,17 +185,6 @@ export default {
currentDashboard
:
this
.
currentDashboard
,
projectPath
:
this
.
projectPath
,
});
this
.
timeWindows
=
timeWindows
;
this
.
selectedTimeWindowKey
=
_
.
escape
(
getParameterValues
(
'
time_window
'
)[
0
])
||
timeWindowsKeyNames
.
eightHours
;
// Set default time window if the selectedTimeWindowKey is bogus
if
(
!
Object
.
keys
(
this
.
timeWindows
).
includes
(
this
.
selectedTimeWindowKey
))
{
this
.
selectedTimeWindowKey
=
timeWindowsKeyNames
.
eightHours
;
}
this
.
selectedTimeWindow
=
this
.
timeWindows
[
this
.
selectedTimeWindowKey
];
},
beforeDestroy
()
{
if
(
sidebarMutationObserver
)
{
...
...
@@ -205,7 +195,20 @@ export default {
if
(
!
this
.
hasMetrics
)
{
this
.
setGettingStartedEmptyState
();
}
else
{
this
.
fetchData
(
getTimeDiff
(
this
.
selectedTimeWindow
));
const
defaultRange
=
getTimeDiff
();
const
start
=
getParameterValues
(
'
start
'
)[
0
]
||
defaultRange
.
start
;
const
end
=
getParameterValues
(
'
end
'
)[
0
]
||
defaultRange
.
end
;
const
range
=
{
start
,
end
,
};
this
.
timeWindows
=
timeWindows
;
this
.
selectedTimeWindowKey
=
getTimeWindow
(
range
);
this
.
selectedTimeWindow
=
this
.
timeWindows
[
this
.
selectedTimeWindowKey
];
this
.
fetchData
(
range
);
sidebarMutationObserver
=
new
MutationObserver
(
this
.
onSidebarMutation
);
sidebarMutationObserver
.
observe
(
document
.
querySelector
(
'
.layout-page
'
),
{
...
...
@@ -259,7 +262,8 @@ export default {
return
this
.
timeWindows
[
key
]
===
this
.
selectedTimeWindow
;
},
setTimeWindowParameter
(
key
)
{
return
`?time_window=
${
key
}
`
;
const
{
start
,
end
}
=
getTimeDiff
(
key
);
return
`?start=
${
encodeURIComponent
(
start
)}
&end=
${
encodeURIComponent
(
end
)}
`
;
},
groupHasData
(
group
)
{
return
this
.
chartsWithData
(
group
.
metrics
).
length
>
0
;
...
...
app/assets/javascripts/monitoring/components/embed.vue
View file @
fc7fab87
<
script
>
import
{
mapActions
,
mapState
}
from
'
vuex
'
;
import
{
getParameterValues
,
removeParams
}
from
'
~/lib/utils/url_utility
'
;
import
GraphGroup
from
'
./graph_group.vue
'
;
import
MonitorAreaChart
from
'
./charts/area.vue
'
;
import
{
sidebarAnimationDuration
,
timeWindowsKeyNames
,
timeWindows
}
from
'
../constants
'
;
import
{
sidebarAnimationDuration
}
from
'
../constants
'
;
import
{
getTimeDiff
}
from
'
../utils
'
;
let
sidebarMutationObserver
;
...
...
@@ -19,10 +20,17 @@ export default {
},
},
data
()
{
const
defaultRange
=
getTimeDiff
();
const
start
=
getParameterValues
(
'
start
'
,
this
.
dashboardUrl
)[
0
]
||
defaultRange
.
start
;
const
end
=
getParameterValues
(
'
end
'
,
this
.
dashboardUrl
)[
0
]
||
defaultRange
.
end
;
const
params
=
{
start
,
end
,
};
return
{
params
:
{
...
getTimeDiff
(
timeWindows
[
timeWindowsKeyNames
.
eightHours
]),
},
params
,
elWidth
:
0
,
};
},
...
...
@@ -73,7 +81,7 @@ export default {
prometheusEndpointEnabled
:
true
,
});
this
.
setEndpoints
({
dashboardEndpoint
:
this
.
dashboardUrl
,
dashboardEndpoint
:
removeParams
([
'
start
'
,
'
end
'
],
this
.
dashboardUrl
)
,
});
this
.
setShowErrorBanner
(
false
);
},
...
...
app/assets/javascripts/monitoring/constants.js
View file @
fc7fab87
...
...
@@ -21,11 +21,19 @@ export const timeWindows = {
oneWeek
:
__
(
'
1 week
'
),
};
export
const
timeWindowsKeyNames
=
{
thirtyMinutes
:
'
thirtyMinutes
'
,
threeHours
:
'
threeHours
'
,
eightHours
:
'
eightHours
'
,
oneDay
:
'
oneDay
'
,
threeDays
:
'
threeDays
'
,
oneWeek
:
'
oneWeek
'
,
export
const
secondsIn
=
{
thirtyMinutes
:
60
*
30
,
threeHours
:
60
*
60
*
3
,
eightHours
:
60
*
60
*
8
,
oneDay
:
60
*
60
*
24
*
1
,
threeDays
:
60
*
60
*
24
*
3
,
oneWeek
:
60
*
60
*
24
*
7
*
1
,
};
export
const
timeWindowsKeyNames
=
Object
.
keys
(
secondsIn
).
reduce
(
(
otherTimeWindows
,
timeWindow
)
=>
({
...
otherTimeWindows
,
[
timeWindow
]:
timeWindow
,
}),
{},
);
app/assets/javascripts/monitoring/stores/actions.js
View file @
fc7fab87
...
...
@@ -151,7 +151,7 @@ function fetchPrometheusResult(prometheusEndpoint, params) {
*/
export
const
fetchPrometheusMetric
=
({
commit
},
{
metric
,
params
})
=>
{
const
{
start
,
end
}
=
params
;
const
timeDiff
=
end
-
start
;
const
timeDiff
=
(
new
Date
(
end
)
-
new
Date
(
start
))
/
1000
;
const
minStep
=
60
;
const
queryDataPoints
=
600
;
...
...
app/assets/javascripts/monitoring/utils.js
View file @
fc7fab87
import
{
timeWindow
s
}
from
'
./constants
'
;
import
{
secondsIn
,
timeWindowsKeyName
s
}
from
'
./constants
'
;
/**
* method that converts a predetermined time window to minutes
* defaults to 8 hours as the default option
* @param {String} timeWindow - The time window to convert to minutes
* @returns {number} The time window in minutes
*/
const
getTimeDifferenceSeconds
=
timeWindow
=>
{
switch
(
timeWindow
)
{
case
timeWindows
.
thirtyMinutes
:
return
60
*
30
;
case
timeWindows
.
threeHours
:
return
60
*
60
*
3
;
case
timeWindows
.
oneDay
:
return
60
*
60
*
24
*
1
;
case
timeWindows
.
threeDays
:
return
60
*
60
*
24
*
3
;
case
timeWindows
.
oneWeek
:
return
60
*
60
*
24
*
7
*
1
;
default
:
return
60
*
60
*
8
;
}
};
export
const
getTimeDiff
=
timeWindow
=>
{
const
end
=
Math
.
floor
(
Date
.
now
()
/
1000
);
// convert milliseconds to seconds
const
difference
=
secondsIn
[
timeWindow
]
||
secondsIn
.
eightHours
;
const
start
=
end
-
difference
;
export
const
getTimeDiff
=
selectedTimeWindow
=>
{
const
end
=
Date
.
now
()
/
1000
;
// convert milliseconds to seconds
const
start
=
end
-
getTimeDifferenceSeconds
(
selectedTimeWindow
);
return
{
start
,
end
};
return
{
start
:
new
Date
(
start
*
1000
).
toISOString
(),
end
:
new
Date
(
end
*
1000
).
toISOString
(),
};
};
export
const
getTimeWindow
=
({
start
,
end
})
=>
Object
.
entries
(
secondsIn
).
reduce
((
acc
,
[
timeRange
,
value
])
=>
{
if
(
end
-
start
===
value
)
{
return
timeRange
;
}
return
acc
;
},
timeWindowsKeyNames
.
eightHours
);
/**
* This method is used to validate if the graph data format for a chart component
* that needs a time series as a response from a prometheus query (query_range) is
...
...
changelogs/unreleased/62973-specify-time-frame-in-shareable-link-for-embedding-metrics.yml
0 → 100644
View file @
fc7fab87
---
title
:
Allow links to metrics dashboard at a specific time
merge_request
:
31283
author
:
type
:
added
spec/frontend/lib/utils/url_utility_spec.js
View file @
fc7fab87
...
...
@@ -34,6 +34,41 @@ describe('URL utility', () => {
});
});
describe
(
'
getParameterValues
'
,
()
=>
{
beforeEach
(()
=>
{
setWindowLocation
({
href
:
'
https://gitlab.com?test=passing&multiple=1&multiple=2
'
,
// make our fake location act like real window.location.toString
// URL() (used in getParameterValues) does this if passed an object
toString
()
{
return
this
.
href
;
},
});
});
it
(
'
returns empty array for no params
'
,
()
=>
{
expect
(
urlUtils
.
getParameterValues
()).
toEqual
([]);
});
it
(
'
returns empty array for non-matching params
'
,
()
=>
{
expect
(
urlUtils
.
getParameterValues
(
'
notFound
'
)).
toEqual
([]);
});
it
(
'
returns single match
'
,
()
=>
{
expect
(
urlUtils
.
getParameterValues
(
'
test
'
)).
toEqual
([
'
passing
'
]);
});
it
(
'
returns multiple matches
'
,
()
=>
{
expect
(
urlUtils
.
getParameterValues
(
'
multiple
'
)).
toEqual
([
'
1
'
,
'
2
'
]);
});
it
(
'
accepts url as second arg
'
,
()
=>
{
const
url
=
'
https://gitlab.com?everything=works
'
;
expect
(
urlUtils
.
getParameterValues
(
'
everything
'
,
url
)).
toEqual
([
'
works
'
]);
expect
(
urlUtils
.
getParameterValues
(
'
test
'
,
url
)).
toEqual
([]);
});
});
describe
(
'
mergeUrlParams
'
,
()
=>
{
it
(
'
adds w
'
,
()
=>
{
expect
(
urlUtils
.
mergeUrlParams
({
w
:
1
},
'
#frag
'
)).
toBe
(
'
?w=1#frag
'
);
...
...
spec/javascripts/monitoring/dashboard_spec.js
View file @
fc7fab87
...
...
@@ -307,7 +307,7 @@ describe('Dashboard', () => {
});
spyOn
(
component
.
$store
,
'
dispatch
'
).
and
.
stub
();
const
getTimeDiffSpy
=
spyOnDependency
(
Dashboard
,
'
getTimeDiff
'
);
const
getTimeDiffSpy
=
spyOnDependency
(
Dashboard
,
'
getTimeDiff
'
)
.
and
.
callThrough
()
;
component
.
$store
.
commit
(
`monitoringDashboard/
${
types
.
RECEIVE_ENVIRONMENTS_DATA_SUCCESS
}
`
,
...
...
@@ -319,7 +319,7 @@ describe('Dashboard', () => {
Vue
.
nextTick
()
.
then
(()
=>
{
expect
(
component
.
$store
.
dispatch
).
toHaveBeenCalled
();
expect
(
getTimeDiffSpy
).
toHaveBeenCalled
With
(
component
.
selectedTimeWindow
);
expect
(
getTimeDiffSpy
).
toHaveBeenCalled
(
);
done
();
})
...
...
@@ -327,7 +327,17 @@ describe('Dashboard', () => {
});
it
(
'
shows a specific time window selected from the url params
'
,
done
=>
{
spyOnDependency
(
Dashboard
,
'
getParameterValues
'
).
and
.
returnValue
([
'
thirtyMinutes
'
]);
const
start
=
1564439536
;
const
end
=
1564441336
;
spyOnDependency
(
Dashboard
,
'
getTimeDiff
'
).
and
.
returnValue
({
start
,
end
,
});
spyOnDependency
(
Dashboard
,
'
getParameterValues
'
).
and
.
callFake
(
param
=>
{
if
(
param
===
'
start
'
)
return
[
start
];
if
(
param
===
'
end
'
)
return
[
end
];
return
[];
});
component
=
new
DashboardComponent
({
el
:
document
.
querySelector
(
'
.prometheus-graphs
'
),
...
...
spec/javascripts/monitoring/store/actions_spec.js
View file @
fc7fab87
...
...
@@ -313,8 +313,8 @@ describe('Monitoring store actions', () => {
it
(
'
commits prometheus query result
'
,
done
=>
{
const
commit
=
jasmine
.
createSpy
();
const
params
=
{
start
:
'
1557216349.469
'
,
end
:
'
1557218149.469
'
,
start
:
'
2019-08-06T12:40:02.184Z
'
,
end
:
'
2019-08-06T20:40:02.184Z
'
,
};
const
metric
=
metricsDashboardResponse
.
dashboard
.
panel_groups
[
0
].
panels
[
0
].
metrics
[
0
];
const
state
=
storeState
();
...
...
spec/javascripts/monitoring/utils_spec.js
View file @
fc7fab87
...
...
@@ -3,28 +3,38 @@ import { timeWindows } from '~/monitoring/constants';
import
{
graphDataPrometheusQuery
,
graphDataPrometheusQueryRange
}
from
'
./mock_data
'
;
describe
(
'
getTimeDiff
'
,
()
=>
{
function
secondsBetween
({
start
,
end
})
{
return
(
new
Date
(
end
)
-
new
Date
(
start
))
/
1000
;
}
function
minutesBetween
(
timeRange
)
{
return
secondsBetween
(
timeRange
)
/
60
;
}
function
hoursBetween
(
timeRange
)
{
return
minutesBetween
(
timeRange
)
/
60
;
}
it
(
'
defaults to an 8 hour (28800s) difference
'
,
()
=>
{
const
params
=
getTimeDiff
();
expect
(
params
.
end
-
params
.
start
).
toEqual
(
28800
);
expect
(
hoursBetween
(
params
)).
toEqual
(
8
);
});
it
(
'
accepts time window as an argument
'
,
()
=>
{
const
params
=
getTimeDiff
(
timeWindows
.
thirtyMinutes
);
const
params
=
getTimeDiff
(
'
thirtyMinutes
'
);
expect
(
params
.
end
-
params
.
start
).
not
.
toEqual
(
2880
0
);
expect
(
minutesBetween
(
params
)).
toEqual
(
3
0
);
});
it
(
'
returns a value for every defined time window
'
,
()
=>
{
const
nonDefaultWindows
=
Object
.
keys
(
timeWindows
).
filter
(
window
=>
window
!==
'
eightHours
'
);
nonDefaultWindows
.
forEach
(
window
=>
{
const
params
=
getTimeDiff
(
timeWindows
[
window
]);
const
diff
=
params
.
end
-
params
.
start
;
nonDefaultWindows
.
forEach
(
timeWindow
=>
{
const
params
=
getTimeDiff
(
timeWindow
);
// Ensure we're not returning the default, 28800 (the # of seconds in 8 hrs)
expect
(
diff
).
not
.
toEqual
(
28800
);
expect
(
typeof
diff
).
toEqual
(
'
number
'
);
// Ensure we're not returning the default
expect
(
hoursBetween
(
params
)).
not
.
toEqual
(
8
);
});
});
});
...
...
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