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
fa4e0d5d
Commit
fa4e0d5d
authored
May 06, 2021
by
David Pisek
Committed by
Savas Vedova
May 06, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add named-list type go generic reports
parent
d9468939
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
241 additions
and
14 deletions
+241
-14
ee/app/assets/javascripts/vulnerabilities/components/generic_report/types/constants.js
...nerabilities/components/generic_report/types/constants.js
+2
-0
ee/app/assets/javascripts/vulnerabilities/components/generic_report/types/list.vue
.../vulnerabilities/components/generic_report/types/list.vue
+4
-4
ee/app/assets/javascripts/vulnerabilities/components/generic_report/types/named_list.vue
...rabilities/components/generic_report/types/named_list.vue
+38
-0
ee/app/assets/javascripts/vulnerabilities/components/generic_report/types/utils.js
.../vulnerabilities/components/generic_report/types/utils.js
+64
-8
ee/app/assets/stylesheets/page_bundles/security_dashboard.scss
...p/assets/stylesheets/page_bundles/security_dashboard.scss
+43
-0
ee/changelogs/unreleased/324891-fe-generic-report-schema-render-named-list-type-on-vulnerability-d.yml
...port-schema-render-named-list-type-on-vulnerability-d.yml
+5
-0
ee/spec/frontend/vulnerabilities/generic_report/types/list_spec.js
...rontend/vulnerabilities/generic_report/types/list_spec.js
+3
-2
ee/spec/frontend/vulnerabilities/generic_report/types/named_list_spec.js
...d/vulnerabilities/generic_report/types/named_list_spec.js
+58
-0
ee/spec/frontend/vulnerabilities/generic_report/types/utils_spec.js
...ontend/vulnerabilities/generic_report/types/utils_spec.js
+24
-0
No files found.
ee/app/assets/javascripts/vulnerabilities/components/generic_report/types/constants.js
View file @
fa4e0d5d
...
@@ -4,12 +4,14 @@ export const REPORT_TYPES = {
...
@@ -4,12 +4,14 @@ export const REPORT_TYPES = {
list
:
'
list
'
,
list
:
'
list
'
,
url
:
'
url
'
,
url
:
'
url
'
,
diff
:
'
diff
'
,
diff
:
'
diff
'
,
namedList
:
'
named-list
'
,
};
};
const
REPORT_TYPE_TO_COMPONENT_MAP
=
{
const
REPORT_TYPE_TO_COMPONENT_MAP
=
{
[
REPORT_TYPES
.
list
]:
()
=>
import
(
'
./list.vue
'
),
[
REPORT_TYPES
.
list
]:
()
=>
import
(
'
./list.vue
'
),
[
REPORT_TYPES
.
url
]:
()
=>
import
(
'
./url.vue
'
),
[
REPORT_TYPES
.
url
]:
()
=>
import
(
'
./url.vue
'
),
[
REPORT_TYPES
.
diff
]:
()
=>
import
(
'
./diff.vue
'
),
[
REPORT_TYPES
.
diff
]:
()
=>
import
(
'
./diff.vue
'
),
[
REPORT_TYPES
.
namedList
]:
()
=>
import
(
'
./named_list.vue
'
),
};
};
export
const
getComponentNameForType
=
(
reportType
)
=>
export
const
getComponentNameForType
=
(
reportType
)
=>
...
...
ee/app/assets/javascripts/vulnerabilities/components/generic_report/types/list.vue
View file @
fa4e0d5d
<
script
>
<
script
>
import
{
is
ListType
}
from
'
./utils
'
;
import
{
is
OfTypeList
}
from
'
./utils
'
;
export
default
{
export
default
{
is
ListType
,
is
OfTypeList
,
components
:
{
components
:
{
ReportItem
:
()
=>
import
(
'
../report_item.vue
'
),
ReportItem
:
()
=>
import
(
'
../report_item.vue
'
),
},
},
...
@@ -15,7 +15,7 @@ export default {
...
@@ -15,7 +15,7 @@ export default {
},
},
computed
:
{
computed
:
{
hasNestedListItems
()
{
hasNestedListItems
()
{
return
this
.
items
.
some
(
is
ListType
);
return
this
.
items
.
some
(
is
OfTypeList
);
},
},
},
},
};
};
...
@@ -25,7 +25,7 @@ export default {
...
@@ -25,7 +25,7 @@ export default {
<li
<li
v-for=
"item in items"
v-for=
"item in items"
:key=
"item.name"
:key=
"item.name"
:class=
"
{ 'gl-list-style-none!': $options.is
ListType
(item) }"
:class=
"
{ 'gl-list-style-none!': $options.is
OfTypeList
(item) }"
>
>
<report-item
:item=
"item"
data-testid=
"reportItem"
/>
<report-item
:item=
"item"
data-testid=
"reportItem"
/>
</li>
</li>
...
...
ee/app/assets/javascripts/vulnerabilities/components/generic_report/types/named_list.vue
0 → 100644
View file @
fa4e0d5d
<
script
>
export
default
{
components
:
{
ReportItem
:
()
=>
import
(
'
../report_item.vue
'
),
},
inheritAttrs
:
false
,
props
:
{
items
:
{
type
:
Array
,
required
:
false
,
default
:
()
=>
[],
},
},
computed
:
{
hasItems
()
{
return
this
.
items
.
length
>
0
;
},
},
};
</
script
>
<
template
>
<div
class=
"gl-display-table"
>
<ul
v-if=
"hasItems"
class=
"generic-report-named-list"
>
<li
v-for=
"
{ label, ...values } in items"
:key="label"
class="generic-report-named-list-item"
data-testid="listItem"
>
<strong
class=
"generic-report-named-list-label"
>
{{
label
}}
</strong>
<span
class=
"generic-report-named-list-value"
>
<report-item
:item=
"values"
:data-testid=
"`listValue$
{label}`" />
</span>
</li>
</ul>
</div>
</
template
>
ee/app/assets/javascripts/vulnerabilities/components/generic_report/types/utils.js
View file @
fa4e0d5d
import
{
overEvery
}
from
'
lodash
'
;
import
{
overEvery
,
flow
}
from
'
lodash
'
;
import
{
REPORT_TYPES
}
from
'
./constants
'
;
import
{
REPORT_TYPES
}
from
'
./constants
'
;
/**
/**
...
@@ -9,13 +9,29 @@ import { REPORT_TYPES } from './constants';
...
@@ -9,13 +9,29 @@ import { REPORT_TYPES } from './constants';
*/
*/
const
isSupportedType
=
({
type
})
=>
Object
.
values
(
REPORT_TYPES
).
includes
(
type
);
const
isSupportedType
=
({
type
})
=>
Object
.
values
(
REPORT_TYPES
).
includes
(
type
);
/**
* Higher order function that accepts a type and returns a function that returns true if the passed in report type matches
*
* @param {*} typeToCheck
* @returns
*/
const
isOfType
=
(
typeToCheck
)
=>
({
type
})
=>
type
===
typeToCheck
;
/**
/**
* Check if the given report is of type list
* Check if the given report is of type list
*
*
* @param {{ type: string } } reportItem
* @param {{ type: string } } reportItem
* @returns boolean
* @returns boolean
*/
*/
export
const
isListType
=
({
type
})
=>
type
===
REPORT_TYPES
.
list
;
export
const
isOfTypeList
=
isOfType
(
REPORT_TYPES
.
list
);
/**
* Check if the given report is of type named-list
*
* @param {{ type: string } } reportItem
* @returns boolean
*/
export
const
isOfTypeNamedList
=
isOfType
(
REPORT_TYPES
.
namedList
);
/**
/**
* Check if the current report item is of that list and is not nested deeper than the maximum depth
* Check if the current report item is of that list and is not nested deeper than the maximum depth
...
@@ -23,8 +39,8 @@ export const isListType = ({ type }) => type === REPORT_TYPES.list;
...
@@ -23,8 +39,8 @@ export const isListType = ({ type }) => type === REPORT_TYPES.list;
* @param {number} maxDepth
* @param {number} maxDepth
* @returns {function}
* @returns {function}
*/
*/
const
isNot
ListType
DeeperThan
=
(
maxDepth
)
=>
(
item
,
currentDepth
)
=>
{
const
isNot
OfTypeList
DeeperThan
=
(
maxDepth
)
=>
(
item
,
currentDepth
)
=>
{
return
!
is
ListType
(
item
)
||
maxDepth
>
currentDepth
+
1
;
return
!
is
OfTypeList
(
item
)
||
maxDepth
>
currentDepth
+
1
;
};
};
/**
/**
...
@@ -44,7 +60,7 @@ const deepFilterListItems = (items, { condition, currentDepth = 0 }) =>
...
@@ -44,7 +60,7 @@ const deepFilterListItems = (items, { condition, currentDepth = 0 }) =>
const
nextItem
=
{
...
currentItem
};
const
nextItem
=
{
...
currentItem
};
if
(
is
ListType
(
nextItem
))
{
if
(
is
OfTypeList
(
nextItem
))
{
nextItem
.
items
=
deepFilterListItems
(
currentItem
.
items
,
{
nextItem
.
items
=
deepFilterListItems
(
currentItem
.
items
,
{
condition
,
condition
,
currentDepth
:
currentDepth
+
1
,
currentDepth
:
currentDepth
+
1
,
...
@@ -61,7 +77,7 @@ const deepFilterListItems = (items, { condition, currentDepth = 0 }) =>
...
@@ -61,7 +77,7 @@ const deepFilterListItems = (items, { condition, currentDepth = 0 }) =>
* @returns {{*}}
* @returns {{*}}
*/
*/
const
filterNestedListsItems
=
(
condition
)
=>
([
label
,
reportItem
])
=>
{
const
filterNestedListsItems
=
(
condition
)
=>
([
label
,
reportItem
])
=>
{
const
filtered
=
is
ListType
(
reportItem
)
const
filtered
=
is
OfTypeList
(
reportItem
)
?
{
?
{
...
reportItem
,
...
reportItem
,
items
:
deepFilterListItems
(
reportItem
.
items
,
{
condition
}),
items
:
deepFilterListItems
(
reportItem
.
items
,
{
condition
}),
...
@@ -71,6 +87,41 @@ const filterNestedListsItems = (condition) => ([label, reportItem]) => {
...
@@ -71,6 +87,41 @@ const filterNestedListsItems = (condition) => ([label, reportItem]) => {
return
[
label
,
filtered
];
return
[
label
,
filtered
];
};
};
/**
* Takes an entry from the vulnerability's details object and removes unsupported
* report types from `named-list` types
*
* @param {function} filterFn
* @param {number} maxDepth
* @returns
*/
const
overEveryNamedListItem
=
(
fn
)
=>
([
label
,
reportItem
])
=>
{
const
filtered
=
isOfTypeNamedList
(
reportItem
)
?
{
...
reportItem
,
items
:
fn
(
reportItem
.
items
),
}
:
reportItem
;
return
[
label
,
filtered
];
};
/**
* Takes an object of the shape
* {
* label1: { ... }
* label2: { ... }
* }
* and returns an array of the shape
* [{ label: 'label1', ... }, { label: 'label2', ...}]
*
* @param {*} items
* @returns
*/
const
transformItemsIntoArray
=
(
items
)
=>
{
return
Object
.
entries
(
items
).
map
(([
label
,
value
])
=>
({
...
value
,
label
}));
};
/**
/**
* Takes a vulnerabilities details object - containing generic report data
* Takes a vulnerabilities details object - containing generic report data
* Returns a copy of the report data with the following items being filtered:
* Returns a copy of the report data with the following items being filtered:
...
@@ -84,11 +135,16 @@ const filterNestedListsItems = (condition) => ([label, reportItem]) => {
...
@@ -84,11 +135,16 @@ const filterNestedListsItems = (condition) => ([label, reportItem]) => {
*/
*/
export
const
filterTypesAndLimitListDepth
=
(
data
,
{
maxDepth
=
5
}
=
{})
=>
{
export
const
filterTypesAndLimitListDepth
=
(
data
,
{
maxDepth
=
5
}
=
{})
=>
{
const
entries
=
Object
.
entries
(
data
);
const
entries
=
Object
.
entries
(
data
);
const
filterCriteria
=
overEvery
([
isSupportedType
,
isNot
ListType
DeeperThan
(
maxDepth
)]);
const
filterCriteria
=
overEvery
([
isSupportedType
,
isNot
OfTypeList
DeeperThan
(
maxDepth
)]);
const
filteredEntries
=
entries
const
filteredEntries
=
entries
.
filter
(([,
reportItem
])
=>
isSupportedType
(
reportItem
))
.
filter
(([,
reportItem
])
=>
isSupportedType
(
reportItem
))
.
map
(
filterNestedListsItems
(
filterCriteria
));
.
map
(
flow
([
filterNestedListsItems
(
filterCriteria
),
overEveryNamedListItem
(
flow
([
filterTypesAndLimitListDepth
,
transformItemsIntoArray
])),
]),
);
return
Object
.
fromEntries
(
filteredEntries
);
return
Object
.
fromEntries
(
filteredEntries
);
};
};
ee/app/assets/stylesheets/page_bundles/security_dashboard.scss
View file @
fa4e0d5d
...
@@ -147,6 +147,8 @@ $selection-summary-with-error-height: 118px;
...
@@ -147,6 +147,8 @@ $selection-summary-with-error-height: 118px;
}
}
.generic-report-list
{
.generic-report-list
{
margin-bottom
:
0
!
important
;
li
{
li
{
@include
gl-ml-0
;
@include
gl-ml-0
;
@include
gl-list-style-none
;
@include
gl-list-style-none
;
...
@@ -157,3 +159,44 @@ $selection-summary-with-error-height: 118px;
...
@@ -157,3 +159,44 @@ $selection-summary-with-error-height: 118px;
list-style-type
:
disc
;
list-style-type
:
disc
;
}
}
}
}
.generic-report-named-list
{
@include
gl-display-grid
;
grid-template-columns
:
max-content
auto
;
margin
:
0
!
important
;
>
.generic-report-named-list-item
{
display
:
contents
;
}
}
.generic-report-named-list-item
{
@include
gl-list-style-none
;
margin
:
0
!
important
;
.generic-report-named-list-label
,
.generic-report-named-list-value
{
@include
gl-m-0
;
@include
gl-display-flex
;
@include
gl-pr-5
;
@include
gl-py-3
;
@include
gl-border-b-1
;
@include
gl-border-b-solid
;
@include
gl-border-gray-100
;
}
&
:first-child
{
>
.generic-report-named-list-label
,
>
.generic-report-named-list-value
{
@include
gl-pt-0
;
}
}
&
:last-child
{
>
.generic-report-named-list-label
,
>
.generic-report-named-list-value
{
@include
gl-pb-0
;
@include
gl-border-b-0
;
}
}
}
ee/changelogs/unreleased/324891-fe-generic-report-schema-render-named-list-type-on-vulnerability-d.yml
0 → 100644
View file @
fa4e0d5d
---
title
:
Add support for rendering "named-list" types on generic vulnerability reports
merge_request
:
60370
author
:
type
:
added
ee/spec/frontend/vulnerabilities/generic_report/types/list_spec.js
View file @
fa4e0d5d
import
{
screen
}
from
'
@testing-library/dom
'
;
import
{
screen
}
from
'
@testing-library/dom
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
REPORT_TYPES
}
from
'
ee/vulnerabilities/components/generic_report/types/constants
'
;
import
List
from
'
ee/vulnerabilities/components/generic_report/types/list.vue
'
;
import
List
from
'
ee/vulnerabilities/components/generic_report/types/list.vue
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
const
TEST_DATA
=
{
const
TEST_DATA
=
{
items
:
[
items
:
[
{
type
:
'
url
'
,
href
:
'
http://foo.bar
'
},
{
type
:
REPORT_TYPES
.
url
,
href
:
'
http://foo.bar
'
},
{
type
:
'
url
'
,
href
:
'
http://bar.baz
'
},
{
type
:
REPORT_TYPES
.
url
,
href
:
'
http://bar.baz
'
},
],
],
};
};
...
...
ee/spec/frontend/vulnerabilities/generic_report/types/named_list_spec.js
0 → 100644
View file @
fa4e0d5d
import
{
shallowMount
}
from
'
@vue/test-utils
'
;
import
{
REPORT_TYPES
}
from
'
ee/vulnerabilities/components/generic_report/types/constants
'
;
import
NamedList
from
'
ee/vulnerabilities/components/generic_report/types/named_list.vue
'
;
import
{
extendedWrapper
}
from
'
helpers/vue_test_utils_helper
'
;
const
TEST_DATA
=
{
items
:
[
{
label
:
'
url1
'
,
type
:
REPORT_TYPES
.
url
,
href
:
'
http://foo.bar
'
},
{
label
:
'
url2
'
,
type
:
REPORT_TYPES
.
url
,
href
:
'
http://bar.baz
'
},
],
};
describe
(
'
ee/vulnerabilities/components/generic_report/types/named_list.vue
'
,
()
=>
{
let
wrapper
;
const
createWrapper
=
()
=>
extendedWrapper
(
shallowMount
(
NamedList
,
{
propsData
:
{
...
TEST_DATA
,
},
// manual stubbing is needed because the component is dynamically imported
stubs
:
{
ReportItem
:
true
,
},
}),
);
const
findList
=
()
=>
wrapper
.
findByRole
(
'
list
'
);
const
findAllListItems
=
()
=>
wrapper
.
findAllByTestId
(
'
listItem
'
);
const
findItemValueWithLabel
=
(
label
)
=>
wrapper
.
findByTestId
(
`listValue
${
label
}
`
);
beforeEach
(()
=>
{
wrapper
=
createWrapper
();
});
afterEach
(()
=>
{
wrapper
.
destroy
();
});
it
(
'
renders a list element
'
,
()
=>
{
expect
(
findList
().
exists
()).
toBe
(
true
);
});
it
(
'
renders all list items
'
,
()
=>
{
expect
(
findAllListItems
()).
toHaveLength
(
Object
.
values
(
TEST_DATA
.
items
).
length
);
});
describe
.
each
(
TEST_DATA
.
items
)(
'
list item: %s
'
,
(
item
)
=>
{
it
(
`renders the item's label`
,
()
=>
{
expect
(
wrapper
.
findByText
(
item
.
label
).
exists
()).
toBe
(
true
);
});
it
(
'
renders a report-item
'
,
()
=>
{
expect
(
findItemValueWithLabel
(
item
.
label
).
exists
()).
toBe
(
true
);
});
});
});
ee/spec/frontend/vulnerabilities/generic_report/types/utils_spec.js
View file @
fa4e0d5d
...
@@ -40,6 +40,15 @@ const TEST_DATA = {
...
@@ -40,6 +40,15 @@ const TEST_DATA = {
{
type
:
MOCK_REPORT_TYPE_UNSUPPORTED
},
{
type
:
MOCK_REPORT_TYPE_UNSUPPORTED
},
],
],
},
},
namedList
:
{
type
:
REPORT_TYPES
.
namedList
,
name
:
'
rootNamedList
'
,
items
:
{
url1
:
{
type
:
REPORT_TYPES
.
url
,
name
:
'
foo
'
},
url2
:
{
type
:
REPORT_TYPES
.
url
,
name
:
'
bar
'
},
unsupported
:
{
type
:
MOCK_REPORT_TYPE_UNSUPPORTED
},
},
},
};
};
describe
(
'
ee/vulnerabilities/components/generic_report/types/utils
'
,
()
=>
{
describe
(
'
ee/vulnerabilities/components/generic_report/types/utils
'
,
()
=>
{
...
@@ -70,5 +79,20 @@ describe('ee/vulnerabilities/components/generic_report/types/utils', () => {
...
@@ -70,5 +79,20 @@ describe('ee/vulnerabilities/components/generic_report/types/utils', () => {
expect
(
includesUnsupportedType
(
getListAtCurrentDepth
(
filteredData
).
items
)).
toBe
(
false
);
expect
(
includesUnsupportedType
(
getListAtCurrentDepth
(
filteredData
).
items
)).
toBe
(
false
);
});
});
});
});
describe
(
'
with named lists
'
,
()
=>
{
const
filteredData
=
filterTypesAndLimitListDepth
(
TEST_DATA
);
it
(
'
filters items with types that are not supported
'
,
()
=>
{
expect
(
includesUnsupportedType
(
filteredData
.
namedList
.
items
)).
toBe
(
false
);
});
it
(
'
transforms the items object into an array of report-items with labels
'
,
()
=>
{
expect
(
filteredData
.
namedList
.
items
).
toEqual
([
{
label
:
'
url1
'
,
type
:
REPORT_TYPES
.
url
,
name
:
'
foo
'
},
{
label
:
'
url2
'
,
type
:
REPORT_TYPES
.
url
,
name
:
'
bar
'
},
]);
});
});
});
});
});
});
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