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
8f1a83be
Commit
8f1a83be
authored
Nov 08, 2021
by
Paul Gascou-Vaillancourt
Committed by
David O'Regan
Nov 08, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Truncate long table values in on-demand scans page
parent
98c1df08
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
161 additions
and
31 deletions
+161
-31
ee/app/assets/javascripts/on_demand_scans/components/tabs/all.vue
...ssets/javascripts/on_demand_scans/components/tabs/all.vue
+4
-0
ee/app/assets/javascripts/on_demand_scans/components/tabs/base_tab.vue
.../javascripts/on_demand_scans/components/tabs/base_tab.vue
+28
-4
ee/spec/frontend/fixtures/on_demand_dast_scans.rb
ee/spec/frontend/fixtures/on_demand_dast_scans.rb
+1
-0
ee/spec/frontend/on_demand_scans/components/tabs/__snapshots__/all_spec.js.snap
...mand_scans/components/tabs/__snapshots__/all_spec.js.snap
+4
-0
ee/spec/frontend/on_demand_scans/components/tabs/base_tab_spec.js
...frontend/on_demand_scans/components/tabs/base_tab_spec.js
+124
-27
No files found.
ee/app/assets/javascripts/on_demand_scans/components/tabs/all.vue
View file @
8f1a83be
...
@@ -12,6 +12,7 @@ export default {
...
@@ -12,6 +12,7 @@ export default {
{
{
label
:
__
(
'
Status
'
),
label
:
__
(
'
Status
'
),
key
:
'
detailedStatus
'
,
key
:
'
detailedStatus
'
,
columnClass
:
'
gl-w-15
'
,
},
},
{
{
label
:
__
(
'
Name
'
),
label
:
__
(
'
Name
'
),
...
@@ -20,6 +21,7 @@ export default {
...
@@ -20,6 +21,7 @@ export default {
{
{
label
:
s__
(
'
OnDemandScans|Scan type
'
),
label
:
s__
(
'
OnDemandScans|Scan type
'
),
key
:
'
scanType
'
,
key
:
'
scanType
'
,
columnClass
:
'
gl-w-13
'
,
},
},
{
{
label
:
s__
(
'
OnDemandScans|Target
'
),
label
:
s__
(
'
OnDemandScans|Target
'
),
...
@@ -28,10 +30,12 @@ export default {
...
@@ -28,10 +30,12 @@ export default {
{
{
label
:
__
(
'
Start date
'
),
label
:
__
(
'
Start date
'
),
key
:
'
createdAt
'
,
key
:
'
createdAt
'
,
columnClass
:
'
gl-w-15
'
,
},
},
{
{
label
:
__
(
'
Pipeline
'
),
label
:
__
(
'
Pipeline
'
),
key
:
'
id
'
,
key
:
'
id
'
,
columnClass
:
'
gl-w-13
'
,
},
},
],
],
i18n
:
{
i18n
:
{
...
...
ee/app/assets/javascripts/on_demand_scans/components/tabs/base_tab.vue
View file @
8f1a83be
...
@@ -7,6 +7,7 @@ import {
...
@@ -7,6 +7,7 @@ import {
GlKeysetPagination
,
GlKeysetPagination
,
GlAlert
,
GlAlert
,
GlSkeletonLoader
,
GlSkeletonLoader
,
GlTruncate
,
}
from
'
@gitlab/ui
'
;
}
from
'
@gitlab/ui
'
;
import
CiBadgeLink
from
'
~/vue_shared/components/ci_badge_link.vue
'
;
import
CiBadgeLink
from
'
~/vue_shared/components/ci_badge_link.vue
'
;
import
TimeAgoTooltip
from
'
~/vue_shared/components/time_ago_tooltip.vue
'
;
import
TimeAgoTooltip
from
'
~/vue_shared/components/time_ago_tooltip.vue
'
;
...
@@ -36,6 +37,7 @@ export default {
...
@@ -36,6 +37,7 @@ export default {
GlKeysetPagination
,
GlKeysetPagination
,
GlAlert
,
GlAlert
,
GlSkeletonLoader
,
GlSkeletonLoader
,
GlTruncate
,
CiBadgeLink
,
CiBadgeLink
,
TimeAgoTooltip
,
TimeAgoTooltip
,
EmptyState
,
EmptyState
,
...
@@ -122,9 +124,8 @@ export default {
...
@@ -122,9 +124,8 @@ export default {
return
this
.
pipelines
?.
pageInfo
;
return
this
.
pipelines
?.
pageInfo
;
},
},
tableFields
()
{
tableFields
()
{
return
this
.
fields
.
map
(({
key
,
label
})
=>
({
return
this
.
fields
.
map
((
field
)
=>
({
key
,
...
field
,
label
,
class
:
[
'
gl-text-black-normal
'
],
class
:
[
'
gl-text-black-normal
'
],
thClass
:
[
'
gl-bg-transparent!
'
,
'
gl-white-space-nowrap
'
],
thClass
:
[
'
gl-bg-transparent!
'
,
'
gl-white-space-nowrap
'
],
}));
}));
...
@@ -188,7 +189,12 @@ export default {
...
@@ -188,7 +189,12 @@ export default {
:items=
"pipelineNodes"
:items=
"pipelineNodes"
:busy=
"$apollo.queries.pipelines.loading"
:busy=
"$apollo.queries.pipelines.loading"
stacked=
"md"
stacked=
"md"
fixed
>
>
<template
#table-colgroup
="
scope
"
>
<col
v-for=
"field in scope.fields"
:key=
"field.key"
:class=
"field.columnClass"
/>
</
template
>
<
template
#table-busy
>
<
template
#table-busy
>
<gl-skeleton-loader
v-for=
"i in 20"
:key=
"i"
:width=
"1000"
:height=
"45"
>
<gl-skeleton-loader
v-for=
"i in 20"
:key=
"i"
:width=
"1000"
:height=
"45"
>
<rect
width=
"85"
height=
"20"
x=
"0"
y=
"5"
rx=
"4"
/>
<rect
width=
"85"
height=
"20"
x=
"0"
y=
"5"
rx=
"4"
/>
...
@@ -205,12 +211,30 @@ export default {
...
@@ -205,12 +211,30 @@ export default {
</div>
</div>
</
template
>
</
template
>
<!-- eslint-disable-next-line vue/valid-v-slot -->
<
template
#cell(dastProfile.name)=
"{ item }"
>
<gl-truncate
v-if=
"item.dastProfile"
:text=
"item.dastProfile.name"
with-tooltip
/>
</
template
>
<
template
#cell
(
scanType
)
>
<
template
#cell
(
scanType
)
>
{{
$options
.
DAST_SHORT_NAME
}}
{{
$options
.
DAST_SHORT_NAME
}}
</
template
>
</
template
>
<!-- eslint-disable-next-line vue/valid-v-slot -->
<
template
#cell(dastProfile.dastSiteProfile.targetUrl)=
"{ item }"
>
<gl-truncate
v-if=
"item.dastProfile"
:text=
"item.dastProfile.dastSiteProfile.targetUrl"
with-tooltip
/>
</
template
>
<
template
#cell(createdAt)=
"{ item }"
>
<
template
#cell(createdAt)=
"{ item }"
>
<time-ago-tooltip
v-if=
"item.createdAt"
:time=
"item.createdAt"
tooltip-placement=
"left"
/>
<time-ago-tooltip
v-if=
"item.createdAt"
class=
"gl-white-space-nowrap"
:time=
"item.createdAt"
/>
</
template
>
</
template
>
<
template
#cell(id)=
"{ item }"
>
<
template
#cell(id)=
"{ item }"
>
...
...
ee/spec/frontend/fixtures/on_demand_dast_scans.rb
View file @
8f1a83be
...
@@ -15,6 +15,7 @@ RSpec.describe 'On-demand DAST scans (GraphQL fixtures)' do
...
@@ -15,6 +15,7 @@ RSpec.describe 'On-demand DAST scans (GraphQL fixtures)' do
path
=
'on_demand_scans/graphql/on_demand_scans.query.graphql'
path
=
'on_demand_scans/graphql/on_demand_scans.query.graphql'
before
do
before
do
stub_licensed_features
(
security_on_demand_scans:
true
)
project
.
add_developer
(
current_user
)
project
.
add_developer
(
current_user
)
end
end
...
...
ee/spec/frontend/on_demand_scans/components/tabs/__snapshots__/all_spec.js.snap
View file @
8f1a83be
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
exports[`AllTab renders the base tab with the correct props 1`] = `
exports[`AllTab renders the base tab with the correct props 1`] = `
Array [
Array [
Object {
Object {
"columnClass": "gl-w-15",
"key": "detailedStatus",
"key": "detailedStatus",
"label": "Status",
"label": "Status",
},
},
...
@@ -11,6 +12,7 @@ Array [
...
@@ -11,6 +12,7 @@ Array [
"label": "Name",
"label": "Name",
},
},
Object {
Object {
"columnClass": "gl-w-13",
"key": "scanType",
"key": "scanType",
"label": "Scan type",
"label": "Scan type",
},
},
...
@@ -19,10 +21,12 @@ Array [
...
@@ -19,10 +21,12 @@ Array [
"label": "Target",
"label": "Target",
},
},
Object {
Object {
"columnClass": "gl-w-15",
"key": "createdAt",
"key": "createdAt",
"label": "Start date",
"label": "Start date",
},
},
Object {
Object {
"columnClass": "gl-w-13",
"key": "id",
"key": "id",
"label": "Pipeline",
"label": "Pipeline",
},
},
...
...
ee/spec/frontend/on_demand_scans/components/tabs/base_tab_spec.js
View file @
8f1a83be
import
{
GlTab
,
GlTable
,
GlAlert
}
from
'
@gitlab/ui
'
;
import
{
GlTab
,
GlTable
,
GlAlert
}
from
'
@gitlab/ui
'
;
import
{
createLocalVue
}
from
'
@vue/test-utils
'
;
import
{
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
{
merge
}
from
'
lodash
'
;
import
allPipelinesWithPipelinesMock
from
'
test_fixtures/graphql/on_demand_scans/graphql/on_demand_scans.query.graphql.with_pipelines.json
'
;
import
allPipelinesWithPipelinesMock
from
'
test_fixtures/graphql/on_demand_scans/graphql/on_demand_scans.query.graphql.with_pipelines.json
'
;
import
allPipelinesWithoutPipelinesMock
from
'
test_fixtures/graphql/on_demand_scans/graphql/on_demand_scans.query.graphql.without_pipelines.json
'
;
import
allPipelinesWithoutPipelinesMock
from
'
test_fixtures/graphql/on_demand_scans/graphql/on_demand_scans.query.graphql.without_pipelines.json
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
stubComponent
}
from
'
helpers/stub_component
'
;
import
{
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
mountExtended
,
shallowMountExtended
}
from
'
helpers/vue_test_utils_helper
'
;
import
BaseTab
from
'
ee/on_demand_scans/components/tabs/base_tab.vue
'
;
import
BaseTab
from
'
ee/on_demand_scans/components/tabs/base_tab.vue
'
;
import
EmptyState
from
'
ee/on_demand_scans/components/empty_state.vue
'
;
import
EmptyState
from
'
ee/on_demand_scans/components/empty_state.vue
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
...
@@ -13,6 +14,7 @@ import { createRouter } from 'ee/on_demand_scans/router';
...
@@ -13,6 +14,7 @@ import { createRouter } from 'ee/on_demand_scans/router';
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
waitForPromises
from
'
helpers/wait_for_promises
'
;
import
{
scrollToElement
}
from
'
~/lib/utils/common_utils
'
;
import
{
scrollToElement
}
from
'
~/lib/utils/common_utils
'
;
import
setWindowLocation
from
'
helpers/set_window_location_helper
'
;
import
setWindowLocation
from
'
helpers/set_window_location_helper
'
;
import
{
getIdFromGraphQLId
}
from
'
~/graphql_shared/utils
'
;
jest
.
mock
(
'
~/lib/utils/common_utils
'
);
jest
.
mock
(
'
~/lib/utils/common_utils
'
);
...
@@ -44,25 +46,52 @@ describe('BaseTab', () => {
...
@@ -44,25 +46,52 @@ describe('BaseTab', () => {
return
wrapper
.
vm
.
$nextTick
();
return
wrapper
.
vm
.
$nextTick
();
};
};
const
createComponent
=
(
propsData
)
=>
{
const
createComponent
Factory
=
(
mountFn
=
shallowMountExtended
)
=>
(
options
=
{}
)
=>
{
router
=
createRouter
();
router
=
createRouter
();
wrapper
=
shallowMountExtended
(
BaseTab
,
{
wrapper
=
mountFn
(
localVue
,
BaseTab
,
apolloProvider
:
createMockApolloProvider
(),
merge
(
router
,
{
propsData
:
{
localVue
,
title
:
'
All
'
,
apolloProvider
:
createMockApolloProvider
(),
query
:
onDemandScansQuery
,
router
,
itemsCount
:
0
,
propsData
:
{
fields
:
[{
name
:
'
ID
'
,
key
:
'
id
'
}],
title
:
'
All
'
,
...
propsData
,
query
:
onDemandScansQuery
,
},
itemsCount
:
0
,
provide
:
{
fields
:
[
projectPath
,
{
},
label
:
'
Status
'
,
stubs
:
{
key
:
'
detailedStatus
'
,
GlTab
:
stubComponent
(
GlTab
,
{
},
template
:
`
{
label
:
'
Name
'
,
key
:
'
dastProfile.name
'
,
},
{
label
:
'
OnDemandScans|Scan type
'
,
key
:
'
scanType
'
,
},
{
label
:
'
OnDemandScans|Target
'
,
key
:
'
dastProfile.dastSiteProfile.targetUrl
'
,
},
{
label
:
'
Start date
'
,
key
:
'
createdAt
'
,
},
{
label
:
'
Pipeline
'
,
key
:
'
id
'
,
},
],
},
provide
:
{
projectPath
,
},
stubs
:
{
GlTab
:
stubComponent
(
GlTab
,
{
template
:
`
<div>
<div>
<span data-testid="tab-title">
<span data-testid="tab-title">
<slot name="title" />
<slot name="title" />
...
@@ -70,14 +99,20 @@ describe('BaseTab', () => {
...
@@ -70,14 +99,20 @@ describe('BaseTab', () => {
<slot />
<slot />
</div>
</div>
`
,
`
,
}),
}),
GlTable
:
stubComponent
(
GlTable
,
{
GlTable
:
stubComponent
(
GlTable
,
{
props
:
[
'
items
'
,
'
busy
'
],
props
:
[
'
items
'
,
'
busy
'
],
}),
}),
},
},
});
},
options
,
),
);
};
};
const
createComponent
=
createComponentFactory
();
const
createFullComponent
=
createComponentFactory
(
mountExtended
);
beforeEach
(()
=>
{
beforeEach
(()
=>
{
requestHandler
=
jest
.
fn
().
mockResolvedValue
(
allPipelinesWithPipelinesMock
);
requestHandler
=
jest
.
fn
().
mockResolvedValue
(
allPipelinesWithPipelinesMock
);
});
});
...
@@ -127,11 +162,13 @@ describe('BaseTab', () => {
...
@@ -127,11 +162,13 @@ describe('BaseTab', () => {
describe
(
'
when there are pipelines
'
,
()
=>
{
describe
(
'
when there are pipelines
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
createComponent
({
createComponent
({
itemsCount
:
30
,
propsData
:
{
itemsCount
:
30
,
},
});
});
});
});
it
(
'
renders the title with the item count
'
,
()
=>
{
it
(
'
renders the title with the item count
'
,
async
()
=>
{
expect
(
findTitle
().
text
()).
toMatchInterpolatedText
(
'
All 30
'
);
expect
(
findTitle
().
text
()).
toMatchInterpolatedText
(
'
All 30
'
);
});
});
...
@@ -171,6 +208,66 @@ describe('BaseTab', () => {
...
@@ -171,6 +208,66 @@ describe('BaseTab', () => {
});
});
});
});
describe
(
'
rendered cells
'
,
()
=>
{
const
[
firstPipeline
]
=
allPipelinesWithPipelinesMock
.
data
.
project
.
pipelines
.
nodes
;
const
findFirstRow
=
()
=>
wrapper
.
find
(
'
tbody > tr
'
);
const
findCellAt
=
(
index
)
=>
findFirstRow
().
findAll
(
'
td
'
).
at
(
index
);
beforeEach
(()
=>
{
createFullComponent
({
propsData
:
{
itemsCount
:
30
,
},
stubs
:
{
GlTable
:
false
,
},
});
});
it
(
'
renders the status badge
'
,
()
=>
{
const
statusCell
=
findCellAt
(
0
);
expect
(
statusCell
.
text
()).
toBe
(
firstPipeline
.
detailedStatus
.
text
);
});
it
(
'
renders the name with GlTruncate
'
,
()
=>
{
const
nameCell
=
findCellAt
(
1
);
const
truncateContainer
=
nameCell
.
find
(
'
[data-testid="truncate-end-container"]
'
);
expect
(
truncateContainer
.
exists
()).
toBe
(
true
);
expect
(
truncateContainer
.
text
()).
toBe
(
firstPipeline
.
dastProfile
.
name
);
});
it
(
'
renders the scan type
'
,
()
=>
{
const
scanTypeCell
=
findCellAt
(
2
);
expect
(
scanTypeCell
.
text
()).
toBe
(
'
DAST
'
);
});
it
(
'
renders the target URL with GlTruncate
'
,
()
=>
{
const
targetUrlCell
=
findCellAt
(
3
);
const
truncateContainer
=
targetUrlCell
.
find
(
'
[data-testid="truncate-end-container"]
'
);
expect
(
truncateContainer
.
exists
()).
toBe
(
true
);
expect
(
truncateContainer
.
text
()).
toBe
(
firstPipeline
.
dastProfile
.
dastSiteProfile
.
targetUrl
);
});
it
(
'
renders the start date as a timeElement
'
,
()
=>
{
const
startDateCell
=
findCellAt
(
4
);
const
timeElement
=
startDateCell
.
find
(
'
time
'
);
expect
(
timeElement
.
exists
()).
toBe
(
true
);
expect
(
timeElement
.
attributes
(
'
datetime
'
)).
toBe
(
firstPipeline
.
createdAt
);
});
it
(
'
renders the pipeline ID
'
,
()
=>
{
const
pipelineIdCell
=
findCellAt
(
5
);
expect
(
pipelineIdCell
.
text
()).
toBe
(
`#
${
getIdFromGraphQLId
(
firstPipeline
.
id
)}
`
);
});
});
describe
(
'
when there are no pipelines
'
,
()
=>
{
describe
(
'
when there are no pipelines
'
,
()
=>
{
beforeEach
(()
=>
{
beforeEach
(()
=>
{
requestHandler
=
jest
.
fn
().
mockResolvedValue
(
allPipelinesWithoutPipelinesMock
);
requestHandler
=
jest
.
fn
().
mockResolvedValue
(
allPipelinesWithoutPipelinesMock
);
...
...
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