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
1084710e
Commit
1084710e
authored
Jun 10, 2020
by
Sam Beckham
Committed by
Mark Florian
Jun 10, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improves the operations empty state
- Uses the GlEmptyState component - Adds tests for the new component
parent
554042f9
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
69 additions
and
69 deletions
+69
-69
ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue
...javascripts/operations/components/dashboard/dashboard.vue
+43
-31
ee/spec/frontend/operations/components/dashboard/dashboard_spec.js
...rontend/operations/components/dashboard/dashboard_spec.js
+26
-38
No files found.
ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue
View file @
1084710e
<
script
>
import
{
mapState
,
mapActions
}
from
'
vuex
'
;
import
{
GlModal
,
GlModalDirective
,
GlDeprecatedButton
,
GlDashboardSkeleton
}
from
'
@gitlab/ui
'
;
import
{
GlDashboardSkeleton
,
GlButton
,
GlEmptyState
,
GlLink
,
GlModal
,
GlModalDirective
,
}
from
'
@gitlab/ui
'
;
import
VueDraggable
from
'
vuedraggable
'
;
import
ProjectSelector
from
'
~/vue_shared/components/project_selector/project_selector.vue
'
;
import
DashboardProject
from
'
./project.vue
'
;
...
...
@@ -8,9 +15,11 @@ import DashboardProject from './project.vue';
export
default
{
components
:
{
DashboardProject
,
GlModal
,
GlDashboardSkeleton
,
GlDeprecatedButton
,
GlButton
,
GlEmptyState
,
GlLink
,
GlModal
,
ProjectSelector
,
VueDraggable
,
},
...
...
@@ -131,13 +140,15 @@ export default {
<h1
class=
"js-dashboard-title page-title text-nowrap flex-fill"
>
{{
s__
(
'
OperationsDashboard|Operations Dashboard
'
)
}}
</h1>
<gl-
deprecated-
button
<gl-button
v-if=
"projects.length"
v-gl-modal=
"$options.modalId"
class=
"js-add-projects-button btn btn-success"
variant=
"success"
category=
"primary"
data-testid=
"add-projects-button"
>
{{
s__
(
'
OperationsDashboard|Add projects
'
)
}}
</gl-
deprecated-
button>
</gl-button>
</div>
<div
class=
"prepend-top-default"
>
<vue-draggable
...
...
@@ -150,34 +161,35 @@ export default {
<dashboard-project
:project=
"project"
/>
</div>
</vue-draggable>
<div
v-else-if=
"!isLoadingProjects"
class=
"row prepend-top-20 text-center"
>
<div
class=
"col-12 d-flex justify-content-center svg-content"
>
<img
:src=
"emptyDashboardSvgPath"
class=
"js-empty-state-svg col-12 prepend-top-20"
/>
</div>
<h4
class=
"js-title col-12 prepend-top-20"
>
{{
s__
(
'
OperationsDashboard|Add a project to the dashboard
'
)
}}
</h4>
<div
class=
"col-12 d-flex justify-content-center"
>
<span
class=
"js-sub-title mw-460 text-tertiary text-left"
>
{{
s__
(
`OperationsDashboard|The operations dashboard provides a summary of each project's
operational health, including pipeline and alert statuses.`
)
}}
<a
:href=
"emptyDashboardHelpPath"
class=
"js-documentation-link"
>
{{
s__
(
'
OperationsDashboard|More information
'
)
}}
</a>
</span>
</div>
<div
class=
"col-12"
>
<gl-deprecated-button
<gl-dashboard-skeleton
v-else-if=
"isLoadingProjects"
/>
<gl-empty-state
v-else
:title=
"s__(`OperationsDashboard|Add a project to the dashboard`)"
:svg-path=
"emptyDashboardSvgPath"
>
<template
#description
>
{{
s__
(
`OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses.`
,
)
}}
<gl-link
:href=
"emptyDashboardHelpPath"
data-testid=
"documentation-link"
>
{{
s__
(
'
OperationsDashboard|More information
'
)
}}
</gl-link
>
.
</
template
>
<
template
#actions
>
<gl-button
v-gl-modal=
"$options.modalId"
class=
"js-add-projects-button btn btn-success prepend-top-default append-bottom-default"
variant=
"success"
data-testid=
"add-projects-button"
>
{{
s__
(
'
OperationsDashboard|Add projects
'
)
}}
</gl-deprecated-button>
</div>
</div>
<gl-dashboard-skeleton
v-else
/>
</gl-button>
</
template
>
</gl-empty-state>
</div>
</div>
</template>
ee/spec/frontend/operations/components/dashboard/dashboard_spec.js
View file @
1084710e
import
MockAdapter
from
'
axios-mock-adapter
'
;
import
{
mount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
Vuex
from
'
vuex
'
;
import
{
GlEmptyState
}
from
'
@gitlab/ui
'
;
import
Project
from
'
ee/operations/components/dashboard/project.vue
'
;
import
Dashboard
from
'
ee/operations/components/dashboard/dashboard.vue
'
;
import
createStore
from
'
ee/vue_shared/dashboards/store
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
trimText
}
from
'
helpers/text_helper
'
;
import
axios
from
'
~/lib/utils/axios_utils
'
;
import
{
mockProjectData
,
mockText
}
from
'
../../mock_data
'
;
...
...
@@ -19,18 +19,26 @@ describe('dashboard component', () => {
let
wrapper
;
let
mockAxios
;
const
mountComponent
=
()
=>
const
emptyDashboardHelpPath
=
'
/help/user/operations_dashboard/index.html
'
;
const
emptyDashboardSvgPath
=
'
/assets/illustrations/operations-dashboard_empty.svg
'
;
const
mountComponent
=
({
stubs
=
{},
state
=
{}
}
=
{})
=>
mount
(
Dashboard
,
{
store
,
localVue
,
propsData
:
{
addPath
:
mockAddEndpoint
,
listPath
:
mockListEndpoint
,
emptyDashboardSvgPath
:
'
/assets/illustrations/operations-dashboard_empty.svg
'
,
emptyDashboardHelpPath
:
'
/help/user/operations_dashboard/index.html
'
,
emptyDashboardSvgPath
,
emptyDashboardHelpPath
,
},
state
,
stubs
,
});
const
findEmptyState
=
()
=>
wrapper
.
find
(
GlEmptyState
);
const
findAddProjectButton
=
()
=>
wrapper
.
find
(
'
[data-testid=add-projects-button]
'
);
beforeEach
(()
=>
{
mockAxios
=
new
MockAdapter
(
axios
);
mockAxios
.
onGet
(
mockListEndpoint
).
replyOnce
(
200
,
{
projects
:
mockProjectData
(
1
)
});
...
...
@@ -52,17 +60,11 @@ describe('dashboard component', () => {
let
button
;
beforeEach
(()
=>
{
button
=
wrapper
.
element
.
querySelector
(
'
.js-add-projects-button
'
);
button
=
findAddProjectButton
(
);
});
it
(
'
renders add projects text
'
,
()
=>
{
expect
(
button
.
innerText
.
trim
()).
toBe
(
mockText
.
ADD_PROJECTS
);
});
it
(
'
renders the projects modal
'
,
()
=>
{
button
.
click
();
expect
(
wrapper
.
element
.
querySelector
(
'
.add-projects-modal
'
)).
toBeDefined
();
expect
(
button
.
text
()).
toBe
(
mockText
.
ADD_PROJECTS
);
});
describe
(
'
when a project is added
'
,
()
=>
{
...
...
@@ -204,42 +206,28 @@ describe('dashboard component', () => {
});
});
describe
(
'
empty state
'
,
()
=>
{
describe
(
'
when no projects have been added
'
,
()
=>
{
beforeEach
(()
=>
{
store
.
state
.
projects
=
[];
mockAxios
.
reset
();
mockAxios
.
onGet
(
mockListEndpoint
).
replyOnce
(
200
,
{
projects
:
[]
});
wrapper
=
mountComponent
();
});
it
(
'
renders empty state svg after requesting projects with no results
'
,
()
=>
{
const
svgSrc
=
wrapper
.
element
.
querySelector
(
'
.js-empty-state-svg
'
).
src
;
expect
(
svgSrc
).
toMatch
(
mockText
.
EMPTY_SVG_SOURCE
);
});
it
(
'
renders title
'
,
()
=>
{
expect
(
wrapper
.
element
.
querySelector
(
'
.js-title
'
).
innerText
.
trim
()).
toBe
(
mockText
.
EMPTY_TITLE
,
);
store
.
state
.
isLoadingProjects
=
false
;
});
it
(
'
renders sub-title
'
,
()
=>
{
expect
(
trimText
(
wrapper
.
element
.
querySelector
(
'
.js-sub-title
'
).
innerText
)).
toBe
(
mockText
.
EMPTY_SUBTITLE
,
);
it
(
'
should render the empty state
'
,
()
=>
{
expect
(
findEmptyState
().
exists
()).
toBe
(
true
);
});
it
(
'
renders link to
documentation
'
,
()
=>
{
const
link
=
wrapper
.
element
.
querySelector
(
'
.js-documentation-link
'
);
it
(
'
should link to the
documentation
'
,
()
=>
{
const
link
=
findEmptyState
().
find
(
'
[data-testid="documentation-link"]
'
);
expect
(
link
.
innerText
.
trim
()).
toBe
(
'
More information
'
);
expect
(
link
.
exists
()).
toBe
(
true
);
expect
(
link
.
attributes
().
href
).
toEqual
(
emptyDashboardHelpPath
);
});
it
(
'
links to documentati
on
'
,
()
=>
{
const
link
=
wrapper
.
element
.
querySelector
(
'
.js-documentation-link
'
);
it
(
'
should render the add projects butt
on
'
,
()
=>
{
const
button
=
findAddProjectButton
(
);
expect
(
link
.
href
).
toMatch
(
wrapper
.
props
().
emptyDashboardHelpPath
);
expect
(
button
.
exists
()).
toBe
(
true
);
expect
(
button
.
text
()).
toEqual
(
'
Add projects
'
);
});
});
});
...
...
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