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
81084565
Commit
81084565
authored
Apr 21, 2021
by
Sarah Groff Hennigh-Palermo
Committed by
Jose Ivan Vargas
Apr 21, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve performance on generating layers view
parent
0463eb5a
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
446 additions
and
23 deletions
+446
-23
app/assets/javascripts/pipelines/components/graph/graph_component.vue
...avascripts/pipelines/components/graph/graph_component.vue
+4
-21
app/assets/javascripts/pipelines/components/parsing_utils.js
app/assets/javascripts/pipelines/components/parsing_utils.js
+24
-1
spec/frontend/pipelines/__snapshots__/parsing_utils_spec.js.snap
...ontend/pipelines/__snapshots__/parsing_utils_spec.js.snap
+373
-0
spec/frontend/pipelines/parsing_utils_spec.js
spec/frontend/pipelines/parsing_utils_spec.js
+45
-1
No files found.
app/assets/javascripts/pipelines/components/graph/graph_component.vue
View file @
81084565
...
...
@@ -2,6 +2,7 @@
import
{
reportToSentry
}
from
'
../../utils
'
;
import
LinkedGraphWrapper
from
'
../graph_shared/linked_graph_wrapper.vue
'
;
import
LinksLayer
from
'
../graph_shared/links_layer.vue
'
;
import
{
generateColumnsFromLayersListMemoized
}
from
'
../parsing_utils
'
;
import
{
DOWNSTREAM
,
MAIN
,
UPSTREAM
,
ONE_COL_WIDTH
,
STAGE_VIEW
}
from
'
./constants
'
;
import
LinkedPipelinesColumn
from
'
./linked_pipelines_column.vue
'
;
import
StageColumnComponent
from
'
./stage_column_component.vue
'
;
...
...
@@ -74,7 +75,9 @@ export default {
return
this
.
hasDownstreamPipelines
?
this
.
pipeline
.
downstream
:
[];
},
layout
()
{
return
this
.
isStageView
?
this
.
pipeline
.
stages
:
this
.
generateColumnsFromLayersList
();
return
this
.
isStageView
?
this
.
pipeline
.
stages
:
generateColumnsFromLayersListMemoized
(
this
.
pipeline
,
this
.
pipelineLayers
);
},
hasDownstreamPipelines
()
{
return
Boolean
(
this
.
pipeline
?.
downstream
?.
length
>
0
);
...
...
@@ -120,26 +123,6 @@ export default {
this
.
getMeasurements
();
},
methods
:
{
generateColumnsFromLayersList
()
{
return
this
.
pipelineLayers
.
map
((
layers
,
idx
)
=>
{
/*
look up the groups in each layer,
then add each set of layer groups to a stage-like object
*/
const
groups
=
layers
.
map
((
id
)
=>
{
const
{
stageIdx
,
groupIdx
}
=
this
.
pipeline
.
stagesLookup
[
id
];
return
this
.
pipeline
.
stages
?.[
stageIdx
]?.
groups
?.[
groupIdx
];
});
return
{
name
:
''
,
id
:
`layer-
${
idx
}
`
,
status
:
{
action
:
null
},
groups
:
groups
.
filter
(
Boolean
),
};
});
},
getMeasurements
()
{
this
.
measurements
=
{
width
:
this
.
$refs
[
this
.
containerId
].
scrollWidth
,
...
...
app/assets/javascripts/pipelines/components/parsing_utils.js
View file @
81084565
import
{
uniqWith
,
isEqual
}
from
'
lodash
'
;
import
{
isEqual
,
memoize
,
uniqWith
}
from
'
lodash
'
;
import
{
createSankey
}
from
'
./dag/drawing_utils
'
;
/*
...
...
@@ -170,3 +170,26 @@ export const listByLayers = ({ stages }) => {
return
acc
;
},
[]);
};
export
const
generateColumnsFromLayersListBare
=
({
stages
,
stagesLookup
},
pipelineLayers
)
=>
{
return
pipelineLayers
.
map
((
layers
,
idx
)
=>
{
/*
Look up the groups in each layer,
then add each set of layer groups to a stage-like object.
*/
const
groups
=
layers
.
map
((
id
)
=>
{
const
{
stageIdx
,
groupIdx
}
=
stagesLookup
[
id
];
return
stages
[
stageIdx
]?.
groups
?.[
groupIdx
];
});
return
{
name
:
''
,
id
:
`layer-
${
idx
}
`
,
status
:
{
action
:
null
},
groups
:
groups
.
filter
(
Boolean
),
};
});
};
export
const
generateColumnsFromLayersListMemoized
=
memoize
(
generateColumnsFromLayersListBare
);
spec/frontend/pipelines/__snapshots__/parsing_utils_spec.js.snap
0 → 100644
View file @
81084565
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DAG visualization parsing utilities generateColumnsFromLayersList matches the snapshot 1`] = `
Array [
Object {
"groups": Array [
Object {
"__typename": "CiGroup",
"jobs": Array [
Object {
"__typename": "CiJob",
"name": "build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
"needs": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1482/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1482",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
],
"name": "build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
"size": 1,
"stageName": "build",
"status": Object {
"__typename": "DetailedStatus",
"group": "success",
"icon": "status_success",
"label": "passed",
},
},
Object {
"__typename": "CiGroup",
"jobs": Array [
Object {
"__typename": "CiJob",
"name": "build_b",
"needs": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1515/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1515",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
],
"name": "build_b",
"size": 1,
"stageName": "build",
"status": Object {
"__typename": "DetailedStatus",
"group": "success",
"icon": "status_success",
"label": "passed",
},
},
Object {
"__typename": "CiGroup",
"jobs": Array [
Object {
"__typename": "CiJob",
"name": "build_c",
"needs": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1484/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1484",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
],
"name": "build_c",
"size": 1,
"stageName": "build",
"status": Object {
"__typename": "DetailedStatus",
"group": "success",
"icon": "status_success",
"label": "passed",
},
},
Object {
"__typename": "CiGroup",
"jobs": Array [
Object {
"__typename": "CiJob",
"name": "build_d 1/3",
"needs": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1485/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1485",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
Object {
"__typename": "CiJob",
"name": "build_d 2/3",
"needs": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1486/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1486",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
Object {
"__typename": "CiJob",
"name": "build_d 3/3",
"needs": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1487/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1487",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
],
"name": "build_d",
"size": 3,
"stageName": "build",
"status": Object {
"__typename": "DetailedStatus",
"group": "success",
"icon": "status_success",
"label": "passed",
},
},
Object {
"__typename": "CiGroup",
"jobs": Array [
Object {
"__typename": "CiJob",
"name": "test_c",
"needs": Array [],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": null,
"detailsPath": "/root/kinder-pipe/-/pipelines/154",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": null,
},
},
],
"name": "test_c",
"size": 1,
"stageName": "test",
"status": Object {
"__typename": "DetailedStatus",
"group": "success",
"icon": "status_success",
"label": null,
},
},
],
"id": "layer-0",
"name": "",
"status": Object {
"action": null,
},
},
Object {
"groups": Array [
Object {
"__typename": "CiGroup",
"jobs": Array [
Object {
"__typename": "CiJob",
"name": "test_a",
"needs": Array [
"build_c",
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1514/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1514",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
],
"name": "test_a",
"size": 1,
"stageName": "test",
"status": Object {
"__typename": "DetailedStatus",
"group": "success",
"icon": "status_success",
"label": "passed",
},
},
Object {
"__typename": "CiGroup",
"jobs": Array [
Object {
"__typename": "CiJob",
"name": "test_b 1/2",
"needs": Array [
"build_d 3/3",
"build_d 2/3",
"build_d 1/3",
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1489/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1489",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
Object {
"__typename": "CiJob",
"name": "test_b 2/2",
"needs": Array [
"build_d 3/3",
"build_d 2/3",
"build_d 1/3",
"build_b",
"build_a_nlfjkdnlvskfnksvjknlfdjvlvnjdkjdf_nvjkenjkrlngjeknjkl",
],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": Object {
"__typename": "StatusAction",
"buttonTitle": "Retry this job",
"icon": "retry",
"path": "/root/abcd-dag/-/jobs/1490/retry",
"title": "Retry",
},
"detailsPath": "/root/abcd-dag/-/jobs/1490",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": "passed",
},
},
],
"name": "test_b",
"size": 2,
"stageName": "test",
"status": Object {
"__typename": "DetailedStatus",
"group": "success",
"icon": "status_success",
"label": "passed",
},
},
Object {
"__typename": "CiGroup",
"jobs": Array [
Object {
"__typename": "CiJob",
"name": "test_d",
"needs": Array [
"build_b",
],
"scheduledAt": null,
"status": Object {
"__typename": "DetailedStatus",
"action": null,
"detailsPath": "/root/abcd-dag/-/pipelines/153",
"group": "success",
"hasDetails": true,
"icon": "status_success",
"tooltip": null,
},
},
],
"name": "test_d",
"size": 1,
"stageName": "test",
"status": Object {
"__typename": "DetailedStatus",
"group": "success",
"icon": "status_success",
"label": null,
},
},
],
"id": "layer-1",
"name": "",
"status": Object {
"action": null,
},
},
]
`;
spec/frontend/pipelines/
components/dag/
parsing_utils_spec.js
→
spec/frontend/pipelines/parsing_utils_spec.js
View file @
81084565
...
...
@@ -3,12 +3,15 @@ import {
createNodeDict
,
makeLinksFromNodes
,
filterByAncestors
,
generateColumnsFromLayersListBare
,
listByLayers
,
parseData
,
removeOrphanNodes
,
getMaxNodes
,
}
from
'
~/pipelines/components/parsing_utils
'
;
import
{
mockParsedGraphQLNodes
}
from
'
./mock_data
'
;
import
{
mockParsedGraphQLNodes
}
from
'
./components/dag/mock_data
'
;
import
{
generateResponse
,
mockPipelineResponse
}
from
'
./graph/mock_data
'
;
describe
(
'
DAG visualization parsing utilities
'
,
()
=>
{
const
nodeDict
=
createNodeDict
(
mockParsedGraphQLNodes
);
...
...
@@ -108,4 +111,45 @@ describe('DAG visualization parsing utilities', () => {
expect
(
getMaxNodes
(
layerNodes
)).
toBe
(
3
);
});
});
describe
(
'
generateColumnsFromLayersList
'
,
()
=>
{
const
pipeline
=
generateResponse
(
mockPipelineResponse
,
'
root/fungi-xoxo
'
);
const
layers
=
listByLayers
(
pipeline
);
const
columns
=
generateColumnsFromLayersListBare
(
pipeline
,
layers
);
it
(
'
returns stage-like objects with default name, id, and status
'
,
()
=>
{
columns
.
forEach
((
col
,
idx
)
=>
{
expect
(
col
).
toMatchObject
({
name
:
''
,
status
:
{
action
:
null
},
id
:
`layer-
${
idx
}
`
,
});
});
});
it
(
'
creates groups that match the list created in listByLayers
'
,
()
=>
{
columns
.
forEach
((
col
,
idx
)
=>
{
const
groupNames
=
col
.
groups
.
map
(({
name
})
=>
name
);
expect
(
groupNames
).
toEqual
(
layers
[
idx
]);
});
});
it
(
'
looks up the correct group object
'
,
()
=>
{
columns
.
forEach
((
col
)
=>
{
col
.
groups
.
forEach
((
group
)
=>
{
const
groupStage
=
pipeline
.
stages
.
find
((
el
)
=>
el
.
name
===
group
.
stageName
);
const
groupObject
=
groupStage
.
groups
.
find
((
el
)
=>
el
.
name
===
group
.
name
);
expect
(
group
).
toBe
(
groupObject
);
});
});
});
/*
Just as a fallback in case multiple functions change, so tests pass
but the implementation moves away from case.
*/
it
(
'
matches the snapshot
'
,
()
=>
{
expect
(
columns
).
toMatchSnapshot
();
});
});
});
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