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
0
Merge Requests
0
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
Boxiang Sun
gitlab-ce
Commits
b0f2cbce
Commit
b0f2cbce
authored
Mar 17, 2017
by
Filipa Lacerda
Committed by
Alfredo Sumaran
Mar 17, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove UJS actions from pipelines tables
parent
bb1620aa
Changes
48
Hide whitespace changes
Inline
Side-by-side
Showing
48 changed files
with
1790 additions
and
1380 deletions
+1790
-1380
app/assets/javascripts/commit/pipelines/pipelines_bundle.js
app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+5
-4
app/assets/javascripts/commit/pipelines/pipelines_service.js
app/assets/javascripts/commit/pipelines/pipelines_service.js
+0
-44
app/assets/javascripts/commit/pipelines/pipelines_table.js
app/assets/javascripts/commit/pipelines/pipelines_table.js
+76
-70
app/assets/javascripts/environments/components/environment.js
...assets/javascripts/environments/components/environment.js
+5
-9
app/assets/javascripts/environments/components/environment_item.js
...s/javascripts/environments/components/environment_item.js
+3
-5
app/assets/javascripts/environments/components/environments_table.js
...javascripts/environments/components/environments_table.js
+2
-2
app/assets/javascripts/environments/folder/environments_folder_view.js
...vascripts/environments/folder/environments_folder_view.js
+6
-9
app/assets/javascripts/environments/services/environments_service.js
...javascripts/environments/services/environments_service.js
+3
-0
app/assets/javascripts/environments/stores/environments_store.js
...ets/javascripts/environments/stores/environments_store.js
+0
-1
app/assets/javascripts/vue_pipelines_index/components/async_button.js
...avascripts/vue_pipelines_index/components/async_button.js
+92
-0
app/assets/javascripts/vue_pipelines_index/components/pipeline_url.js
...avascripts/vue_pipelines_index/components/pipeline_url.js
+56
-0
app/assets/javascripts/vue_pipelines_index/components/pipelines_actions.js
...ripts/vue_pipelines_index/components/pipelines_actions.js
+71
-0
app/assets/javascripts/vue_pipelines_index/components/pipelines_artifacts.js
...pts/vue_pipelines_index/components/pipelines_artifacts.js
+32
-0
app/assets/javascripts/vue_pipelines_index/components/stage.js
...ssets/javascripts/vue_pipelines_index/components/stage.js
+116
-0
app/assets/javascripts/vue_pipelines_index/components/status.js
...sets/javascripts/vue_pipelines_index/components/status.js
+60
-0
app/assets/javascripts/vue_pipelines_index/components/time_ago.js
...ts/javascripts/vue_pipelines_index/components/time_ago.js
+71
-0
app/assets/javascripts/vue_pipelines_index/event_hub.js
app/assets/javascripts/vue_pipelines_index/event_hub.js
+3
-0
app/assets/javascripts/vue_pipelines_index/index.js
app/assets/javascripts/vue_pipelines_index/index.js
+11
-12
app/assets/javascripts/vue_pipelines_index/pipeline_actions.js
...ssets/javascripts/vue_pipelines_index/pipeline_actions.js
+0
-123
app/assets/javascripts/vue_pipelines_index/pipeline_url.js
app/assets/javascripts/vue_pipelines_index/pipeline_url.js
+0
-63
app/assets/javascripts/vue_pipelines_index/pipelines.js
app/assets/javascripts/vue_pipelines_index/pipelines.js
+112
-78
app/assets/javascripts/vue_pipelines_index/services/pipelines_service.js
...scripts/vue_pipelines_index/services/pipelines_service.js
+44
-0
app/assets/javascripts/vue_pipelines_index/stage.js
app/assets/javascripts/vue_pipelines_index/stage.js
+0
-119
app/assets/javascripts/vue_pipelines_index/status.js
app/assets/javascripts/vue_pipelines_index/status.js
+0
-64
app/assets/javascripts/vue_pipelines_index/store.js
app/assets/javascripts/vue_pipelines_index/store.js
+0
-31
app/assets/javascripts/vue_pipelines_index/stores/pipelines_store.js
...javascripts/vue_pipelines_index/stores/pipelines_store.js
+25
-12
app/assets/javascripts/vue_pipelines_index/time_ago.js
app/assets/javascripts/vue_pipelines_index/time_ago.js
+0
-78
app/assets/javascripts/vue_shared/components/commit.js
app/assets/javascripts/vue_shared/components/commit.js
+150
-157
app/assets/javascripts/vue_shared/components/pipelines_table.js
...sets/javascripts/vue_shared/components/pipelines_table.js
+38
-42
app/assets/javascripts/vue_shared/components/pipelines_table_row.js
.../javascripts/vue_shared/components/pipelines_table_row.js
+211
-182
app/assets/javascripts/vue_shared/components/table_pagination.js
...ets/javascripts/vue_shared/components/table_pagination.js
+121
-133
app/assets/javascripts/vue_shared/vue_resource_interceptor.js
...assets/javascripts/vue_shared/vue_resource_interceptor.js
+6
-4
app/assets/stylesheets/pages/pipelines.scss
app/assets/stylesheets/pages/pipelines.scss
+19
-5
changelogs/unreleased/fl-remove-ujs-pipelines.yml
changelogs/unreleased/fl-remove-ujs-pipelines.yml
+4
-0
spec/features/merge_requests/created_from_fork_spec.rb
spec/features/merge_requests/created_from_fork_spec.rb
+0
-3
spec/features/projects/pipelines/pipelines_spec.rb
spec/features/projects/pipelines/pipelines_spec.rb
+19
-13
spec/javascripts/commit/pipelines/mock_data.js
spec/javascripts/commit/pipelines/mock_data.js
+1
-4
spec/javascripts/commit/pipelines/pipelines_spec.js
spec/javascripts/commit/pipelines/pipelines_spec.js
+6
-11
spec/javascripts/commit/pipelines/pipelines_store_spec.js
spec/javascripts/commit/pipelines/pipelines_store_spec.js
+0
-33
spec/javascripts/vue_pipelines_index/async_button_spec.js
spec/javascripts/vue_pipelines_index/async_button_spec.js
+93
-0
spec/javascripts/vue_pipelines_index/pipeline_url_spec.js
spec/javascripts/vue_pipelines_index/pipeline_url_spec.js
+100
-0
spec/javascripts/vue_pipelines_index/pipelines_actions_spec.js
...javascripts/vue_pipelines_index/pipelines_actions_spec.js
+62
-0
spec/javascripts/vue_pipelines_index/pipelines_artifacts_spec.js
...vascripts/vue_pipelines_index/pipelines_artifacts_spec.js
+40
-0
spec/javascripts/vue_pipelines_index/pipelines_store_spec.js
spec/javascripts/vue_pipelines_index/pipelines_store_spec.js
+72
-0
spec/javascripts/vue_shared/components/commit_spec.js
spec/javascripts/vue_shared/components/commit_spec.js
+13
-14
spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
...scripts/vue_shared/components/pipelines_table_row_spec.js
+7
-7
spec/javascripts/vue_shared/components/pipelines_table_spec.js
...javascripts/vue_shared/components/pipelines_table_spec.js
+15
-16
spec/javascripts/vue_shared/components/table_pagination_spec.js
...avascripts/vue_shared/components/table_pagination_spec.js
+20
-32
No files found.
app/assets/javascripts/commit/pipelines/pipelines_bundle.js
View file @
b0f2cbce
/* eslint-disable no-
new, no-
param-reassign */
/* global Vue, CommitsPipelineStore, PipelinesService, Flash */
/* eslint-disable no-param-reassign */
import
CommitPipelinesTable
from
'
./pipelines_table
'
;
window
.
Vue
=
require
(
'
vue
'
);
require
(
'
./pipelines_table
'
);
window
.
Vue
.
use
(
require
(
'
vue-resource
'
));
/**
* Commits View > Pipelines Tab > Pipelines Table.
* Merge Request View > Pipelines Tab > Pipelines Table.
...
...
@@ -21,7 +22,7 @@ $(() => {
}
const
pipelineTableViewEl
=
document
.
querySelector
(
'
#commit-pipeline-table-view
'
);
gl
.
commits
.
pipelines
.
PipelinesTableBundle
=
new
gl
.
commits
.
pipelines
.
PipelinesTableView
();
gl
.
commits
.
pipelines
.
PipelinesTableBundle
=
new
CommitPipelinesTable
();
if
(
pipelineTableViewEl
&&
pipelineTableViewEl
.
dataset
.
disableInitialization
===
undefined
)
{
gl
.
commits
.
pipelines
.
PipelinesTableBundle
.
$mount
(
pipelineTableViewEl
);
...
...
app/assets/javascripts/commit/pipelines/pipelines_service.js
deleted
100644 → 0
View file @
bb1620aa
/* globals Vue */
/* eslint-disable no-unused-vars, no-param-reassign */
/**
* Pipelines service.
*
* Used to fetch the data used to render the pipelines table.
* Uses Vue.Resource
*/
class
PipelinesService
{
/**
* FIXME: The url provided to request the pipelines in the new merge request
* page already has `.json`.
* This should be fixed when the endpoint is improved.
*
* @param {String} root
*/
constructor
(
root
)
{
let
endpoint
;
if
(
root
.
indexOf
(
'
.json
'
)
===
-
1
)
{
endpoint
=
`
${
root
}
.json`
;
}
else
{
endpoint
=
root
;
}
this
.
pipelines
=
Vue
.
resource
(
endpoint
);
}
/**
* Given the root param provided when the class is initialized, will
* make a GET request.
*
* @return {Promise}
*/
all
()
{
return
this
.
pipelines
.
get
();
}
}
window
.
gl
=
window
.
gl
||
{};
gl
.
commits
=
gl
.
commits
||
{};
gl
.
commits
.
pipelines
=
gl
.
commits
.
pipelines
||
{};
gl
.
commits
.
pipelines
.
PipelinesService
=
PipelinesService
;
app/assets/javascripts/commit/pipelines/pipelines_table.js
View file @
b0f2cbce
/* eslint-disable no-new, no-param-reassign */
/* global Vue, CommitsPipelineStore, PipelinesService, Flash */
window
.
Vue
=
require
(
'
vue
'
);
window
.
Vue
.
use
(
require
(
'
vue-resource
'
));
require
(
'
../../lib/utils/common_utils
'
);
require
(
'
../../vue_shared/vue_resource_interceptor
'
);
require
(
'
../../vue_shared/components/pipelines_table
'
);
require
(
'
./pipelines_service
'
);
const
PipelineStore
=
require
(
'
./pipelines_store
'
);
/* eslint-disable no-new*/
/* global Flash */
import
Vue
from
'
vue
'
;
import
PipelinesTableComponent
from
'
../../vue_shared/components/pipelines_table
'
;
import
PipelinesService
from
'
../../vue_pipelines_index/services/pipelines_service
'
;
import
PipelineStore
from
'
../../vue_pipelines_index/stores/pipelines_store
'
;
import
eventHub
from
'
../../vue_pipelines_index/event_hub
'
;
import
'
../../lib/utils/common_utils
'
;
import
'
../../vue_shared/vue_resource_interceptor
'
;
/**
*
...
...
@@ -20,48 +19,59 @@ const PipelineStore = require('./pipelines_store');
* as soon as we have Webpack and can load them directly into JS files.
*/
(()
=>
{
window
.
gl
=
window
.
gl
||
{};
gl
.
commits
=
gl
.
commits
||
{};
gl
.
commits
.
pipelines
=
gl
.
commits
.
pipelines
||
{};
export
default
Vue
.
component
(
'
pipelines-table
'
,
{
components
:
{
'
pipelines-table-component
'
:
PipelinesTableComponent
,
},
gl
.
commits
.
pipelines
.
PipelinesTableView
=
Vue
.
component
(
'
pipelines-table
'
,
{
/**
* Accesses the DOM to provide the needed data.
* Returns the necessary props to render `pipelines-table-component` component.
*
* @return {Object}
*/
data
()
{
const
pipelinesTableData
=
document
.
querySelector
(
'
#commit-pipeline-table-view
'
).
dataset
;
const
store
=
new
PipelineStore
();
components
:
{
'
pipelines-table-component
'
:
gl
.
pipelines
.
PipelinesTableComponent
,
},
return
{
endpoint
:
pipelinesTableData
.
endpoint
,
store
,
state
:
store
.
state
,
isLoading
:
false
,
};
},
/**
* Accesses the DOM to provide the needed data.
* Returns the necessary props to render `pipelines-table-component` component.
*
* @return {Object}
*/
data
()
{
const
pipelinesTableData
=
document
.
querySelector
(
'
#commit-pipeline-table-view
'
).
dataset
;
const
store
=
new
PipelineStore
();
/**
* When the component is about to be mounted, tell the service to fetch the data
*
* A request to fetch the pipelines will be made.
* In case of a successfull response we will store the data in the provided
* store, in case of a failed response we need to warn the user.
*
*/
beforeMount
()
{
this
.
service
=
new
PipelinesService
(
this
.
endpoint
);
return
{
endpoint
:
pipelinesTableData
.
endpoint
,
store
,
state
:
store
.
state
,
isLoading
:
false
,
};
},
this
.
fetchPipelines
();
eventHub
.
$on
(
'
refreshPipelines
'
,
this
.
fetchPipelines
);
},
beforeUpdate
()
{
if
(
this
.
state
.
pipelines
.
length
&&
this
.
$children
)
{
this
.
store
.
startTimeAgoLoops
.
call
(
this
,
Vue
);
}
},
/**
* When the component is about to be mounted, tell the service to fetch the data
*
* A request to fetch the pipelines will be made.
* In case of a successfull response we will store the data in the provided
* store, in case of a failed response we need to warn the user.
*
*/
beforeMount
()
{
const
pipelinesService
=
new
gl
.
commits
.
pipelines
.
PipelinesService
(
this
.
endpoint
);
beforeDestroyed
()
{
eventHub
.
$off
(
'
refreshPipelines
'
);
},
methods
:
{
fetchPipelines
()
{
this
.
isLoading
=
true
;
return
pipelinesService
.
all
()
return
this
.
service
.
getPipelines
()
.
then
(
response
=>
response
.
json
())
.
then
((
json
)
=>
{
// depending of the endpoint the response can either bring a `pipelines` key or not.
...
...
@@ -71,34 +81,30 @@ const PipelineStore = require('./pipelines_store');
})
.
catch
(()
=>
{
this
.
isLoading
=
false
;
new
Flash
(
'
An error occurred while fetching the pipelines, please reload the page again.
'
,
'
alert
'
);
new
Flash
(
'
An error occurred while fetching the pipelines, please reload the page again.
'
);
});
},
},
beforeUpdate
()
{
if
(
this
.
state
.
pipelines
.
length
&&
this
.
$children
)
{
PipelineStore
.
startTimeAgoLoops
.
call
(
this
,
Vue
);
}
},
template
:
`
<div class="pipelines">
<div class="realtime-loading" v-if="isLoading">
<i class="fa fa-spinner fa-spin"></i>
</div>
template
:
`
<div class="pipelines">
<div class="realtime-loading" v-if="isLoading">
<i class="fa fa-spinner fa-spin"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!isLoading && state.pipelines.length === 0">
<h2 class="blank-state-title js-blank-state-title">
No pipelines to show
</h2>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!isLoading && state.pipelines.length === 0">
<h2 class="blank-state-title js-blank-state-title">
No pipelines to show
</h2>
</div>
<div class="table-holder pipelines"
v-if="!isLoading && state.pipelines.length > 0">
<pipelines-table-component :pipelines="state.pipelines"/>
</div>
<div class="table-holder pipelines"
v-if="!isLoading && state.pipelines.length > 0">
<pipelines-table-component
:pipelines="state.pipelines"
:service="service" />
</div>
`
,
});
})
()
;
</div>
`
,
});
app/assets/javascripts/environments/components/environment.js
View file @
b0f2cbce
/* eslint-disable no-
param-reassign, no-
new */
/* eslint-disable no-new */
/* global Flash */
import
Vue
from
'
vue
'
;
import
EnvironmentsService
from
'
../services/environments_service
'
;
import
EnvironmentTable
from
'
./environments_table
'
;
import
EnvironmentsStore
from
'
../stores/environments_store
'
;
import
TablePaginationComponent
from
'
../../vue_shared/components/table_pagination
'
;
import
'
../../lib/utils/common_utils
'
;
import
eventHub
from
'
../event_hub
'
;
const
Vue
=
window
.
Vue
=
require
(
'
vue
'
);
window
.
Vue
.
use
(
require
(
'
vue-resource
'
));
require
(
'
../../vue_shared/components/table_pagination
'
);
require
(
'
../../lib/utils/common_utils
'
);
require
(
'
../../vue_shared/vue_resource_interceptor
'
);
export
default
Vue
.
component
(
'
environment-component
'
,
{
components
:
{
'
environment-table
'
:
EnvironmentTable
,
'
table-pagination
'
:
gl
.
VueGlPagination
,
'
table-pagination
'
:
TablePaginationComponent
,
},
data
()
{
...
...
@@ -59,7 +56,6 @@ export default Vue.component('environment-component', {
canCreateEnvironmentParsed
()
{
return
gl
.
utils
.
convertPermissionToBoolean
(
this
.
canCreateEnvironment
);
},
},
/**
...
...
app/assets/javascripts/environments/components/environment_item.js
View file @
b0f2cbce
import
Timeago
from
'
timeago.js
'
;
import
'
../../lib/utils/text_utility
'
;
import
ActionsComponent
from
'
./environment_actions
'
;
import
ExternalUrlComponent
from
'
./environment_external_url
'
;
import
StopComponent
from
'
./environment_stop
'
;
import
RollbackComponent
from
'
./environment_rollback
'
;
import
TerminalButtonComponent
from
'
./environment_terminal_button
'
;
import
'
../../lib/utils/text_utility
'
;
import
'
../../vue_shared/components/commit
'
;
import
CommitComponent
from
'
../../vue_shared/components/commit
'
;
/**
* Envrionment Item Component
*
* Renders a table row for each environment.
*/
const
timeagoInstance
=
new
Timeago
();
export
default
{
components
:
{
'
commit-component
'
:
gl
.
CommitComponent
,
'
commit-component
'
:
CommitComponent
,
'
actions-component
'
:
ActionsComponent
,
'
external-url-component
'
:
ExternalUrlComponent
,
'
stop-component
'
:
StopComponent
,
...
...
app/assets/javascripts/environments/components/environments_table.js
View file @
b0f2cbce
/**
* Render environments table.
*/
import
Environment
Item
from
'
./environment_item
'
;
import
Environment
TableRowComponent
from
'
./environment_item
'
;
export
default
{
components
:
{
'
environment-item
'
:
Environment
Item
,
'
environment-item
'
:
Environment
TableRowComponent
,
},
props
:
{
...
...
app/assets/javascripts/environments/folder/environments_folder_view.js
View file @
b0f2cbce
/* eslint-disable no-
param-reassign, no-
new */
/* eslint-disable no-new */
/* global Flash */
import
Vue
from
'
vue
'
;
import
EnvironmentsService
from
'
../services/environments_service
'
;
import
EnvironmentTable
from
'
../components/environments_table
'
;
import
EnvironmentsStore
from
'
../stores/environments_store
'
;
const
Vue
=
window
.
Vue
=
require
(
'
vue
'
);
window
.
Vue
.
use
(
require
(
'
vue-resource
'
));
require
(
'
../../vue_shared/components/table_pagination
'
);
require
(
'
../../lib/utils/common_utils
'
);
require
(
'
../../vue_shared/vue_resource_interceptor
'
);
import
TablePaginationComponent
from
'
../../vue_shared/components/table_pagination
'
;
import
'
../../lib/utils/common_utils
'
;
import
'
../../vue_shared/vue_resource_interceptor
'
;
export
default
Vue
.
component
(
'
environment-folder-view
'
,
{
components
:
{
'
environment-table
'
:
EnvironmentTable
,
'
table-pagination
'
:
gl
.
VueGlPagination
,
'
table-pagination
'
:
TablePaginationComponent
,
},
data
()
{
...
...
app/assets/javascripts/environments/services/environments_service.js
View file @
b0f2cbce
/* eslint-disable class-methods-use-this */
import
Vue
from
'
vue
'
;
import
VueResource
from
'
vue-resource
'
;
Vue
.
use
(
VueResource
);
export
default
class
EnvironmentsService
{
constructor
(
endpoint
)
{
...
...
app/assets/javascripts/environments/stores/environments_store.js
View file @
b0f2cbce
import
'
~/lib/utils/common_utils
'
;
/**
* Environments Store.
*
...
...
app/assets/javascripts/vue_pipelines_index/components/async_button.js
0 → 100644
View file @
b0f2cbce
/* eslint-disable no-new, no-alert */
/* global Flash */
import
'
~/flash
'
;
import
eventHub
from
'
../event_hub
'
;
export
default
{
props
:
{
endpoint
:
{
type
:
String
,
required
:
true
,
},
service
:
{
type
:
Object
,
required
:
true
,
},
title
:
{
type
:
String
,
required
:
true
,
},
icon
:
{
type
:
String
,
required
:
true
,
},
cssClass
:
{
type
:
String
,
required
:
true
,
},
confirmActionMessage
:
{
type
:
String
,
required
:
false
,
},
},
data
()
{
return
{
isLoading
:
false
,
};
},
computed
:
{
iconClass
()
{
return
`fa fa-
${
this
.
icon
}
`
;
},
buttonClass
()
{
return
`btn has-tooltip
${
this
.
cssClass
}
`
;
},
},
methods
:
{
onClick
()
{
if
(
this
.
confirmActionMessage
&&
confirm
(
this
.
confirmActionMessage
))
{
this
.
makeRequest
();
}
else
if
(
!
this
.
confirmActionMessage
)
{
this
.
makeRequest
();
}
},
makeRequest
()
{
this
.
isLoading
=
true
;
this
.
service
.
postAction
(
this
.
endpoint
)
.
then
(()
=>
{
this
.
isLoading
=
false
;
eventHub
.
$emit
(
'
refreshPipelines
'
);
})
.
catch
(()
=>
{
this
.
isLoading
=
false
;
new
Flash
(
'
An error occured while making the request.
'
);
});
},
},
template
:
`
<button
type="button"
@click="onClick"
:class="buttonClass"
:title="title"
:aria-label="title"
data-placement="top"
:disabled="isLoading">
<i :class="iconClass" aria-hidden="true"/>
<i class="fa fa-spinner fa-spin" aria-hidden="true" v-if="isLoading" />
</button>
`
,
};
app/assets/javascripts/vue_pipelines_index/components/pipeline_url.js
0 → 100644
View file @
b0f2cbce
export
default
{
props
:
[
'
pipeline
'
,
],
computed
:
{
user
()
{
return
!!
this
.
pipeline
.
user
;
},
},
template
:
`
<td>
<a
:href="pipeline.path"
class="js-pipeline-url-link">
<span class="pipeline-id">#{{pipeline.id}}</span>
</a>
<span>by</span>
<a
class="js-pipeline-url-user"
v-if="user"
:href="pipeline.user.web_url">
<img
v-if="user"
class="avatar has-tooltip s20 "
:title="pipeline.user.name"
data-container="body"
:src="pipeline.user.avatar_url"
>
</a>
<span
v-if="!user"
class="js-pipeline-url-api api monospace">
API
</span>
<span
v-if="pipeline.flags.latest"
class="js-pipeline-url-lastest label label-success has-tooltip"
title="Latest pipeline for this branch"
data-original-title="Latest pipeline for this branch">
latest
</span>
<span
v-if="pipeline.flags.yaml_errors"
class="js-pipeline-url-yaml label label-danger has-tooltip"
:title="pipeline.yaml_errors"
:data-original-title="pipeline.yaml_errors">
yaml invalid
</span>
<span
v-if="pipeline.flags.stuck"
class="js-pipeline-url-stuck label label-warning">
stuck
</span>
</td>
`
,
};
app/assets/javascripts/vue_pipelines_index/components/pipelines_actions.js
0 → 100644
View file @
b0f2cbce
/* eslint-disable no-new */
/* global Flash */
import
'
~/flash
'
;
import
playIconSvg
from
'
icons/_icon_play.svg
'
;
import
eventHub
from
'
../event_hub
'
;
export
default
{
props
:
{
actions
:
{
type
:
Array
,
required
:
true
,
},
service
:
{
type
:
Object
,
required
:
true
,
},
},
data
()
{
return
{
playIconSvg
,
isLoading
:
false
,
};
},
methods
:
{
onClickAction
(
endpoint
)
{
this
.
isLoading
=
true
;
this
.
service
.
postAction
(
endpoint
)
.
then
(()
=>
{
this
.
isLoading
=
false
;
eventHub
.
$emit
(
'
refreshPipelines
'
);
})
.
catch
(()
=>
{
this
.
isLoading
=
false
;
new
Flash
(
'
An error occured while making the request.
'
);
});
},
},
template
:
`
<div class="btn-group" v-if="actions">
<button
type="button"
class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions"
title="Manual job"
data-toggle="dropdown"
data-placement="top"
aria-label="Manual job"
:disabled="isLoading">
${
playIconSvg
}
<i class="fa fa-caret-down" aria-hidden="true"></i>
<i v-if="isLoading" class="fa fa-spinner fa-spin" aria-hidden="true"></i>
</button>
<ul class="dropdown-menu dropdown-menu-align-right">
<li v-for="action in actions">
<button
type="button"
class="js-pipeline-action-link no-btn"
@click="onClickAction(action.path)">
${
playIconSvg
}
<span>{{action.name}}</span>
</button>
</li>
</ul>
</div>
`
,
};
app/assets/javascripts/vue_pipelines_index/components/pipelines_artifacts.js
0 → 100644
View file @
b0f2cbce
export
default
{
props
:
{
artifacts
:
{
type
:
Array
,
required
:
true
,
},
},
template
:
`
<div class="btn-group" role="group">
<button
class="dropdown-toggle btn btn-default build-artifacts has-tooltip js-pipeline-dropdown-download"
title="Artifacts"
data-placement="top"
data-toggle="dropdown"
aria-label="Artifacts">
<i class="fa fa-download" aria-hidden="true"></i>
<i class="fa fa-caret-down" aria-hidden="true"></i>
</button>
<ul class="dropdown-menu dropdown-menu-align-right">
<li v-for="artifact in artifacts">
<a
rel="nofollow"
:href="artifact.path">
<i class="fa fa-download" aria-hidden="true"></i>
<span>Download {{artifact.name}} artifacts</span>
</a>
</li>
</ul>
</div>
`
,
};
app/assets/javascripts/vue_pipelines_index/components/stage.js
0 → 100644
View file @
b0f2cbce
/* global Flash */
import
canceledSvg
from
'
icons/_icon_status_canceled_borderless.svg
'
;
import
createdSvg
from
'
icons/_icon_status_created_borderless.svg
'
;
import
failedSvg
from
'
icons/_icon_status_failed_borderless.svg
'
;
import
manualSvg
from
'
icons/_icon_status_manual_borderless.svg
'
;
import
pendingSvg
from
'
icons/_icon_status_pending_borderless.svg
'
;
import
runningSvg
from
'
icons/_icon_status_running_borderless.svg
'
;
import
skippedSvg
from
'
icons/_icon_status_skipped_borderless.svg
'
;
import
successSvg
from
'
icons/_icon_status_success_borderless.svg
'
;
import
warningSvg
from
'
icons/_icon_status_warning_borderless.svg
'
;
export
default
{
data
()
{
const
svgsDictionary
=
{
icon_status_canceled
:
canceledSvg
,
icon_status_created
:
createdSvg
,
icon_status_failed
:
failedSvg
,
icon_status_manual
:
manualSvg
,
icon_status_pending
:
pendingSvg
,
icon_status_running
:
runningSvg
,
icon_status_skipped
:
skippedSvg
,
icon_status_success
:
successSvg
,
icon_status_warning
:
warningSvg
,
};
return
{
builds
:
''
,
spinner
:
'
<span class="fa fa-spinner fa-spin"></span>
'
,
svg
:
svgsDictionary
[
this
.
stage
.
status
.
icon
],
};
},
props
:
{
stage
:
{
type
:
Object
,
required
:
true
,
},
},
updated
()
{
if
(
this
.
builds
)
{
this
.
stopDropdownClickPropagation
();
}
},
methods
:
{
fetchBuilds
(
e
)
{
const
ariaExpanded
=
e
.
currentTarget
.
attributes
[
'
aria-expanded
'
];
if
(
ariaExpanded
&&
(
ariaExpanded
.
textContent
===
'
true
'
))
return
null
;
return
this
.
$http
.
get
(
this
.
stage
.
dropdown_path
)
.
then
((
response
)
=>
{
this
.
builds
=
JSON
.
parse
(
response
.
body
).
html
;
},
()
=>
{
const
flash
=
new
Flash
(
'
Something went wrong on our end.
'
);
return
flash
;
});
},
/**
* When the user right clicks or cmd/ctrl + click in the job name
* the dropdown should not be closed and the link should open in another tab,
* so we stop propagation of the click event inside the dropdown.
*
* Since this component is rendered multiple times per page we need to guarantee we only
* target the click event of this component.
*/
stopDropdownClickPropagation
()
{
$
(
this
.
$el
.
querySelectorAll
(
'
.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item
'
)).
on
(
'
click
'
,
(
e
)
=>
{
e
.
stopPropagation
();
});
},
},
computed
:
{
buildsOrSpinner
()
{
return
this
.
builds
?
this
.
builds
:
this
.
spinner
;
},
dropdownClass
()
{
if
(
this
.
builds
)
return
'
js-builds-dropdown-container
'
;
return
'
js-builds-dropdown-loading builds-dropdown-loading
'
;
},
buildStatus
()
{
return
`Build:
${
this
.
stage
.
status
.
label
}
`
;
},
tooltip
()
{
return
`has-tooltip ci-status-icon ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
},
triggerButtonClass
()
{
return
`mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
},
},
template
:
`
<div>
<button
@click="fetchBuilds($event)"
:class="triggerButtonClass"
:title="stage.title"
data-placement="top"
data-toggle="dropdown"
type="button"
:aria-label="stage.title">
<span v-html="svg" aria-hidden="true"></span>
<i class="fa fa-caret-down" aria-hidden="true"></i>
</button>
<ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
<div class="arrow-up" aria-hidden="true"></div>
<div
:class="dropdownClass"
class="js-builds-dropdown-list scrollable-menu"
v-html="buildsOrSpinner">
</div>
</ul>
</div>
`
,
};
app/assets/javascripts/vue_pipelines_index/components/status.js
0 → 100644
View file @
b0f2cbce
import
canceledSvg
from
'
icons/_icon_status_canceled.svg
'
;
import
createdSvg
from
'
icons/_icon_status_created.svg
'
;
import
failedSvg
from
'
icons/_icon_status_failed.svg
'
;
import
manualSvg
from
'
icons/_icon_status_manual.svg
'
;
import
pendingSvg
from
'
icons/_icon_status_pending.svg
'
;
import
runningSvg
from
'
icons/_icon_status_running.svg
'
;
import
skippedSvg
from
'
icons/_icon_status_skipped.svg
'
;
import
successSvg
from
'
icons/_icon_status_success.svg
'
;
import
warningSvg
from
'
icons/_icon_status_warning.svg
'
;
export
default
{
props
:
{
pipeline
:
{
type
:
Object
,
required
:
true
,
},
},
data
()
{
const
svgsDictionary
=
{
icon_status_canceled
:
canceledSvg
,
icon_status_created
:
createdSvg
,
icon_status_failed
:
failedSvg
,
icon_status_manual
:
manualSvg
,
icon_status_pending
:
pendingSvg
,
icon_status_running
:
runningSvg
,
icon_status_skipped
:
skippedSvg
,
icon_status_success
:
successSvg
,
icon_status_warning
:
warningSvg
,
};
return
{
svg
:
svgsDictionary
[
this
.
pipeline
.
details
.
status
.
icon
],
};
},
computed
:
{
cssClasses
()
{
return
`ci-status ci-
${
this
.
pipeline
.
details
.
status
.
group
}
`
;
},
detailsPath
()
{
const
{
status
}
=
this
.
pipeline
.
details
;
return
status
.
has_details
?
status
.
details_path
:
false
;
},
content
()
{
return
`
${
this
.
svg
}
${
this
.
pipeline
.
details
.
status
.
text
}
`
;
},
},
template
:
`
<td class="commit-link">
<a
:class="cssClasses"
:href="detailsPath"
v-html="content">
</a>
</td>
`
,
};
app/assets/javascripts/vue_pipelines_index/components/time_ago.js
0 → 100644
View file @
b0f2cbce
import
iconTimerSvg
from
'
icons/_icon_timer.svg
'
;
import
'
../../lib/utils/datetime_utility
'
;
export
default
{
data
()
{
return
{
currentTime
:
new
Date
(),
iconTimerSvg
,
};
},
props
:
[
'
pipeline
'
],
computed
:
{
timeAgo
()
{
return
gl
.
utils
.
getTimeago
();
},
localTimeFinished
()
{
return
gl
.
utils
.
formatDate
(
this
.
pipeline
.
details
.
finished_at
);
},
timeStopped
()
{
const
changeTime
=
this
.
currentTime
;
const
options
=
{
weekday
:
'
long
'
,
year
:
'
numeric
'
,
month
:
'
short
'
,
day
:
'
numeric
'
,
};
options
.
timeZoneName
=
'
short
'
;
const
finished
=
this
.
pipeline
.
details
.
finished_at
;
if
(
!
finished
&&
changeTime
)
return
false
;
return
({
words
:
this
.
timeAgo
.
format
(
finished
)
});
},
duration
()
{
const
{
duration
}
=
this
.
pipeline
.
details
;
const
date
=
new
Date
(
duration
*
1000
);
let
hh
=
date
.
getUTCHours
();
let
mm
=
date
.
getUTCMinutes
();
let
ss
=
date
.
getSeconds
();
if
(
hh
<
10
)
hh
=
`0
${
hh
}
`
;
if
(
mm
<
10
)
mm
=
`0
${
mm
}
`
;
if
(
ss
<
10
)
ss
=
`0
${
ss
}
`
;
if
(
duration
!==
null
)
return
`
${
hh
}
:
${
mm
}
:
${
ss
}
`
;
return
false
;
},
},
methods
:
{
changeTime
()
{
this
.
currentTime
=
new
Date
();
},
},
template
:
`
<td class="pipelines-time-ago">
<p class="duration" v-if='duration'>
<span v-html="iconTimerSvg"></span>
{{duration}}
</p>
<p class="finished-at" v-if='timeStopped'>
<i class="fa fa-calendar"></i>
<time
data-toggle="tooltip"
data-placement="top"
data-container="body"
:data-original-title='localTimeFinished'>
{{timeStopped.words}}
</time>
</p>
</td>
`
,
};
app/assets/javascripts/vue_pipelines_index/event_hub.js
0 → 100644
View file @
b0f2cbce
import
Vue
from
'
vue
'
;
export
default
new
Vue
();
app/assets/javascripts/vue_pipelines_index/index.js
View file @
b0f2cbce
/* eslint-disable no-param-reassign */
/* global Vue, VueResource, gl */
window
.
Vue
=
require
(
'
vue
'
);
import
PipelinesStore
from
'
./stores/pipelines_store
'
;
import
PipelinesComponent
from
'
./pipelines
'
;
import
'
../vue_shared/vue_resource_interceptor
'
;
const
Vue
=
window
.
Vue
=
require
(
'
vue
'
);
window
.
Vue
.
use
(
require
(
'
vue-resource
'
));
require
(
'
../lib/utils/common_utils
'
);
require
(
'
../vue_shared/vue_resource_interceptor
'
);
require
(
'
./pipelines
'
);
$
(()
=>
new
Vue
({
el
:
document
.
querySelector
(
'
.vue-pipelines-index
'
),
data
()
{
const
project
=
document
.
querySelector
(
'
.pipelines
'
);
const
store
=
new
PipelinesStore
();
return
{
s
cope
:
project
.
dataset
.
url
,
store
:
new
gl
.
PipelineStore
()
,
s
tore
,
endpoint
:
project
.
dataset
.
url
,
};
},
components
:
{
'
vue-pipelines
'
:
gl
.
VuePipelines
,
'
vue-pipelines
'
:
PipelinesComponent
,
},
template
:
`
<vue-pipelines
:scope="scope"
:store="store">
</vue-pipelines>
:endpoint="endpoint"
:store="store" />
`
,
}));
app/assets/javascripts/vue_pipelines_index/pipeline_actions.js
deleted
100644 → 0
View file @
bb1620aa
/* global Vue, Flash, gl */
/* eslint-disable no-param-reassign, no-alert */
const
playIconSvg
=
require
(
'
icons/_icon_play.svg
'
);
((
gl
)
=>
{
gl
.
VuePipelineActions
=
Vue
.
extend
({
props
:
[
'
pipeline
'
],
computed
:
{
actions
()
{
return
this
.
pipeline
.
details
.
manual_actions
.
length
>
0
;
},
artifacts
()
{
return
this
.
pipeline
.
details
.
artifacts
.
length
>
0
;
},
},
methods
:
{
download
(
name
)
{
return
`Download
${
name
}
artifacts`
;
},
/**
* Shows a dialog when the user clicks in the cancel button.
* We need to prevent the default behavior and stop propagation because the
* link relies on UJS.
*
* @param {Event} event
*/
confirmAction
(
event
)
{
if
(
!
confirm
(
'
Are you sure you want to cancel this pipeline?
'
))
{
event
.
preventDefault
();
event
.
stopPropagation
();
}
},
},
data
()
{
return
{
playIconSvg
};
},
template
:
`
<td class="pipeline-actions">
<div class="pull-right">
<div class="btn-group">
<div class="btn-group" v-if="actions">
<button
class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions"
data-toggle="dropdown"
title="Manual job"
data-placement="top"
data-container="body"
aria-label="Manual job">
<span v-html="playIconSvg" aria-hidden="true"></span>
<i class="fa fa-caret-down" aria-hidden="true"></i>
</button>
<ul class="dropdown-menu dropdown-menu-align-right">
<li v-for='action in pipeline.details.manual_actions'>
<a
rel="nofollow"
data-method="post"
:href="action.path" >
<span v-html="playIconSvg" aria-hidden="true"></span>
<span>{{action.name}}</span>
</a>
</li>
</ul>
</div>
<div class="btn-group" v-if="artifacts">
<button
class="dropdown-toggle btn btn-default build-artifacts has-tooltip js-pipeline-dropdown-download"
title="Artifacts"
data-placement="top"
data-container="body"
data-toggle="dropdown"
aria-label="Artifacts">
<i class="fa fa-download" aria-hidden="true"></i>
<i class="fa fa-caret-down" aria-hidden="true"></i>
</button>
<ul class="dropdown-menu dropdown-menu-align-right">
<li v-for='artifact in pipeline.details.artifacts'>
<a
rel="nofollow"
:href="artifact.path">
<i class="fa fa-download" aria-hidden="true"></i>
<span>{{download(artifact.name)}}</span>
</a>
</li>
</ul>
</div>
<div class="btn-group" v-if="pipeline.flags.retryable">
<a
class="btn btn-default btn-retry has-tooltip"
title="Retry"
rel="nofollow"
data-method="post"
data-placement="top"
data-container="body"
data-toggle="dropdown"
:href='pipeline.retry_path'
aria-label="Retry">
<i class="fa fa-repeat" aria-hidden="true"></i>
</a>
</div>
<div class="btn-group" v-if="pipeline.flags.cancelable">
<a
class="btn btn-remove has-tooltip"
title="Cancel"
rel="nofollow"
data-method="post"
data-placement="top"
data-container="body"
data-toggle="dropdown"
:href='pipeline.cancel_path'
aria-label="Cancel">
<i class="fa fa-remove" aria-hidden="true"></i>
</a>
</div>
</div>
</div>
</td>
`
,
});
})(
window
.
gl
||
(
window
.
gl
=
{}));
app/assets/javascripts/vue_pipelines_index/pipeline_url.js
deleted
100644 → 0
View file @
bb1620aa
/* global Vue, gl */
/* eslint-disable no-param-reassign */
((
gl
)
=>
{
gl
.
VuePipelineUrl
=
Vue
.
extend
({
props
:
[
'
pipeline
'
,
],
computed
:
{
user
()
{
return
!!
this
.
pipeline
.
user
;
},
},
template
:
`
<td>
<a :href='pipeline.path'>
<span class="pipeline-id">#{{pipeline.id}}</span>
</a>
<span>by</span>
<a
v-if='user'
:href='pipeline.user.web_url'
>
<img
v-if='user'
class="avatar has-tooltip s20 "
:title='pipeline.user.name'
data-container="body"
:src='pipeline.user.avatar_url'
>
</a>
<span
v-if='!user'
class="api monospace"
>
API
</span>
<span
v-if='pipeline.flags.latest'
class="label label-success has-tooltip"
title="Latest pipeline for this branch"
data-original-title="Latest pipeline for this branch"
>
latest
</span>
<span
v-if='pipeline.flags.yaml_errors'
class="label label-danger has-tooltip"
:title='pipeline.yaml_errors'
:data-original-title='pipeline.yaml_errors'
>
yaml invalid
</span>
<span
v-if='pipeline.flags.stuck'
class="label label-warning"
>
stuck
</span>
</td>
`
,
});
})(
window
.
gl
||
(
window
.
gl
=
{}));
app/assets/javascripts/vue_pipelines_index/pipelines.js
View file @
b0f2cbce
/* global Vue, gl */
/* eslint-disable no-param-reassign */
/* global Flash */
/* eslint-disable no-new */
import
'
~/flash
'
;
import
Vue
from
'
vue
'
;
import
PipelinesService
from
'
./services/pipelines_service
'
;
import
eventHub
from
'
./event_hub
'
;
import
PipelinesTableComponent
from
'
../vue_shared/components/pipelines_table
'
;
import
TablePaginationComponent
from
'
../vue_shared/components/table_pagination
'
;
window
.
Vue
=
require
(
'
vue
'
);
require
(
'
../vue_shared/components/table_pagination
'
);
require
(
'
./store
'
);
require
(
'
../vue_shared/components/pipelines_table
'
);
const
CommitPipelinesStoreWithTimeAgo
=
require
(
'
../commit/pipelines/pipelines_store
'
);
((
gl
)
=>
{
gl
.
VuePipelines
=
Vue
.
extend
({
components
:
{
'
gl-pagination
'
:
gl
.
VueGlPagination
,
'
pipelines-table-component
'
:
gl
.
pipelines
.
PipelinesTableComponent
,
export
default
{
props
:
{
endpoint
:
{
type
:
String
,
required
:
true
,
},
data
()
{
return
{
pipelines
:
[],
timeLoopInterval
:
''
,
intervalId
:
''
,
apiScope
:
'
all
'
,
pageInfo
:
{},
pagenum
:
1
,
count
:
{},
pageRequest
:
false
,
};
},
props
:
[
'
scope
'
,
'
store
'
],
created
()
{
const
pagenum
=
gl
.
utils
.
getParameterByName
(
'
page
'
);
const
scope
=
gl
.
utils
.
getParameterByName
(
'
scope
'
);
if
(
pagenum
)
this
.
pagenum
=
pagenum
;
if
(
scope
)
this
.
apiScope
=
scope
;
this
.
store
.
fetchDataLoop
.
call
(
this
,
Vue
,
this
.
pagenum
,
this
.
scope
,
this
.
apiScope
);
store
:
{
type
:
Object
,
required
:
true
,
},
},
components
:
{
'
gl-pagination
'
:
TablePaginationComponent
,
'
pipelines-table-component
'
:
PipelinesTableComponent
,
},
data
()
{
return
{
state
:
this
.
store
.
state
,
apiScope
:
'
all
'
,
pagenum
:
1
,
pageRequest
:
false
,
};
},
created
()
{
this
.
service
=
new
PipelinesService
(
this
.
endpoint
);
this
.
fetchPipelines
();
eventHub
.
$on
(
'
refreshPipelines
'
,
this
.
fetchPipelines
);
},
beforeUpdate
()
{
if
(
this
.
state
.
pipelines
.
length
&&
this
.
$children
)
{
this
.
store
.
startTimeAgoLoops
.
call
(
this
,
Vue
);
}
},
beforeUpdate
()
{
if
(
this
.
pipelines
.
length
&&
this
.
$children
)
{
CommitPipelinesStoreWithTimeAgo
.
startTimeAgoLoops
.
call
(
this
,
Vue
);
}
beforeDestroyed
()
{
eventHub
.
$off
(
'
refreshPipelines
'
);
},
methods
:
{
/**
* Will change the page number and update the URL.
*
* @param {Number} pageNumber desired page to go to.
*/
change
(
pageNumber
)
{
const
param
=
gl
.
utils
.
setParamInURL
(
'
page
'
,
pageNumber
);
gl
.
utils
.
visitUrl
(
param
);
return
param
;
},
methods
:
{
/**
* Will change the page number and update the URL.
*
* @param {Number} pageNumber desired page to go to.
*/
change
(
pageNumber
)
{
const
param
=
gl
.
utils
.
setParamInURL
(
'
page
'
,
pageNumber
);
gl
.
utils
.
visitUrl
(
param
);
return
param
;
},
fetchPipelines
()
{
const
pageNumber
=
gl
.
utils
.
getParameterByName
(
'
page
'
)
||
this
.
pagenum
;
const
scope
=
gl
.
utils
.
getParameterByName
(
'
scope
'
)
||
this
.
apiScope
;
this
.
pageRequest
=
true
;
return
this
.
service
.
getPipelines
(
scope
,
pageNumber
)
.
then
(
resp
=>
({
headers
:
resp
.
headers
,
body
:
resp
.
json
(),
}))
.
then
((
response
)
=>
{
this
.
store
.
storeCount
(
response
.
body
.
count
);
this
.
store
.
storePipelines
(
response
.
body
.
pipelines
);
this
.
store
.
storePagination
(
response
.
headers
);
})
.
then
(()
=>
{
this
.
pageRequest
=
false
;
})
.
catch
(()
=>
{
this
.
pageRequest
=
false
;
new
Flash
(
'
An error occurred while fetching the pipelines, please reload the page again.
'
);
});
},
template
:
`
<div>
<div class="pipelines realtime-loading" v-if='pageRequest'>
<i class="fa fa-spinner fa-spin"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!pageRequest && pipelines.length === 0">
<h2 class="blank-state-title js-blank-state-title">
No pipelines to show
</h2>
</div>
<div class="table-holder" v-if='!pageRequest && pipelines.length'>
<pipelines-table-component :pipelines='pipelines'/>
</div>
<gl-pagination
v-if='!pageRequest && pipelines.length && pageInfo.total > pageInfo.perPage'
:pagenum='pagenum'
:change='change'
:count='count.all'
:pageInfo='pageInfo'
>
</gl-pagination>
},
template
:
`
<div>
<div class="pipelines realtime-loading" v-if="pageRequest">
<i class="fa fa-spinner fa-spin" aria-hidden="true"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!pageRequest && state.pipelines.length === 0">
<h2 class="blank-state-title js-blank-state-title">
No pipelines to show
</h2>
</div>
<div class="table-holder" v-if="!pageRequest && state.pipelines.length">
<pipelines-table-component
:pipelines="state.pipelines"
:service="service"/>
</div>
`
,
});
})(
window
.
gl
||
(
window
.
gl
=
{}));
<gl-pagination
v-if="!pageRequest && state.pipelines.length && state.pageInfo.total > state.pageInfo.perPage"
:pagenum="pagenum"
:change="change"
:count="state.count.all"
:pageInfo="state.pageInfo"
>
</gl-pagination>
</div>
`
,
};
app/assets/javascripts/vue_pipelines_index/services/pipelines_service.js
0 → 100644
View file @
b0f2cbce
/* eslint-disable class-methods-use-this */
import
Vue
from
'
vue
'
;
import
VueResource
from
'
vue-resource
'
;
Vue
.
use
(
VueResource
);
export
default
class
PipelinesService
{
/**
* Commits and merge request endpoints need to be requested with `.json`.
*
* The url provided to request the pipelines in the new merge request
* page already has `.json`.
*
* @param {String} root
*/
constructor
(
root
)
{
let
endpoint
;
if
(
root
.
indexOf
(
'
.json
'
)
===
-
1
)
{
endpoint
=
`
${
root
}
.json`
;
}
else
{
endpoint
=
root
;
}
this
.
pipelines
=
Vue
.
resource
(
endpoint
);
}
getPipelines
(
scope
,
page
)
{
return
this
.
pipelines
.
get
({
scope
,
page
});
}
/**
* Post request for all pipelines actions.
* Endpoint content type needs to be:
* `Content-Type:application/x-www-form-urlencoded`
*
* @param {String} endpoint
* @return {Promise}
*/
postAction
(
endpoint
)
{
return
Vue
.
http
.
post
(
endpoint
,
{},
{
emulateJSON
:
true
});
}
}
app/assets/javascripts/vue_pipelines_index/stage.js
deleted
100644 → 0
View file @
bb1620aa
/* global Vue, Flash, gl */
/* eslint-disable no-param-reassign */
import
canceledSvg
from
'
icons/_icon_status_canceled_borderless.svg
'
;
import
createdSvg
from
'
icons/_icon_status_created_borderless.svg
'
;
import
failedSvg
from
'
icons/_icon_status_failed_borderless.svg
'
;
import
manualSvg
from
'
icons/_icon_status_manual_borderless.svg
'
;
import
pendingSvg
from
'
icons/_icon_status_pending_borderless.svg
'
;
import
runningSvg
from
'
icons/_icon_status_running_borderless.svg
'
;
import
skippedSvg
from
'
icons/_icon_status_skipped_borderless.svg
'
;
import
successSvg
from
'
icons/_icon_status_success_borderless.svg
'
;
import
warningSvg
from
'
icons/_icon_status_warning_borderless.svg
'
;
((
gl
)
=>
{
gl
.
VueStage
=
Vue
.
extend
({
data
()
{
const
svgsDictionary
=
{
icon_status_canceled
:
canceledSvg
,
icon_status_created
:
createdSvg
,
icon_status_failed
:
failedSvg
,
icon_status_manual
:
manualSvg
,
icon_status_pending
:
pendingSvg
,
icon_status_running
:
runningSvg
,
icon_status_skipped
:
skippedSvg
,
icon_status_success
:
successSvg
,
icon_status_warning
:
warningSvg
,
};
return
{
builds
:
''
,
spinner
:
'
<span class="fa fa-spinner fa-spin"></span>
'
,
svg
:
svgsDictionary
[
this
.
stage
.
status
.
icon
],
};
},
props
:
{
stage
:
{
type
:
Object
,
required
:
true
,
},
},
updated
()
{
if
(
this
.
builds
)
{
this
.
stopDropdownClickPropagation
();
}
},
methods
:
{
fetchBuilds
(
e
)
{
const
areaExpanded
=
e
.
currentTarget
.
attributes
[
'
aria-expanded
'
];
if
(
areaExpanded
&&
(
areaExpanded
.
textContent
===
'
true
'
))
return
null
;
return
this
.
$http
.
get
(
this
.
stage
.
dropdown_path
)
.
then
((
response
)
=>
{
this
.
builds
=
JSON
.
parse
(
response
.
body
).
html
;
},
()
=>
{
const
flash
=
new
Flash
(
'
Something went wrong on our end.
'
);
return
flash
;
});
},
/**
* When the user right clicks or cmd/ctrl + click in the job name
* the dropdown should not be closed and the link should open in another tab,
* so we stop propagation of the click event inside the dropdown.
*
* Since this component is rendered multiple times per page we need to guarantee we only
* target the click event of this component.
*/
stopDropdownClickPropagation
()
{
$
(
this
.
$el
).
on
(
'
click
'
,
'
.js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item
'
,
(
e
)
=>
{
e
.
stopPropagation
();
});
},
},
computed
:
{
buildsOrSpinner
()
{
return
this
.
builds
?
this
.
builds
:
this
.
spinner
;
},
dropdownClass
()
{
if
(
this
.
builds
)
return
'
js-builds-dropdown-container
'
;
return
'
js-builds-dropdown-loading builds-dropdown-loading
'
;
},
buildStatus
()
{
return
`Build:
${
this
.
stage
.
status
.
label
}
`
;
},
tooltip
()
{
return
`has-tooltip ci-status-icon ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
},
triggerButtonClass
()
{
return
`mini-pipeline-graph-dropdown-toggle has-tooltip js-builds-dropdown-button ci-status-icon-
${
this
.
stage
.
status
.
group
}
`
;
},
},
template
:
`
<div>
<button
@click="fetchBuilds($event)"
:class="triggerButtonClass"
:title="stage.title"
data-placement="top"
data-toggle="dropdown"
type="button"
:aria-label="stage.title">
<span v-html="svg" aria-hidden="true"></span>
<i class="fa fa-caret-down" aria-hidden="true"></i>
</button>
<ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
<div class="arrow-up" aria-hidden="true"></div>
<div
:class="dropdownClass"
class="js-builds-dropdown-list scrollable-menu"
v-html="buildsOrSpinner">
</div>
</ul>
</div>
`
,
});
})(
window
.
gl
||
(
window
.
gl
=
{}));
app/assets/javascripts/vue_pipelines_index/status.js
deleted
100644 → 0
View file @
bb1620aa
/* global Vue, gl */
/* eslint-disable no-param-reassign */
import
canceledSvg
from
'
icons/_icon_status_canceled.svg
'
;
import
createdSvg
from
'
icons/_icon_status_created.svg
'
;
import
failedSvg
from
'
icons/_icon_status_failed.svg
'
;
import
manualSvg
from
'
icons/_icon_status_manual.svg
'
;
import
pendingSvg
from
'
icons/_icon_status_pending.svg
'
;
import
runningSvg
from
'
icons/_icon_status_running.svg
'
;
import
skippedSvg
from
'
icons/_icon_status_skipped.svg
'
;
import
successSvg
from
'
icons/_icon_status_success.svg
'
;
import
warningSvg
from
'
icons/_icon_status_warning.svg
'
;
((
gl
)
=>
{
gl
.
VueStatusScope
=
Vue
.
extend
({
props
:
[
'
pipeline
'
,
],
data
()
{
const
svgsDictionary
=
{
icon_status_canceled
:
canceledSvg
,
icon_status_created
:
createdSvg
,
icon_status_failed
:
failedSvg
,
icon_status_manual
:
manualSvg
,
icon_status_pending
:
pendingSvg
,
icon_status_running
:
runningSvg
,
icon_status_skipped
:
skippedSvg
,
icon_status_success
:
successSvg
,
icon_status_warning
:
warningSvg
,
};
return
{
svg
:
svgsDictionary
[
this
.
pipeline
.
details
.
status
.
icon
],
};
},
computed
:
{
cssClasses
()
{
const
cssObject
=
{
'
ci-status
'
:
true
};
cssObject
[
`ci-
${
this
.
pipeline
.
details
.
status
.
group
}
`
]
=
true
;
return
cssObject
;
},
detailsPath
()
{
const
{
status
}
=
this
.
pipeline
.
details
;
return
status
.
has_details
?
status
.
details_path
:
false
;
},
content
()
{
return
`
${
this
.
svg
}
${
this
.
pipeline
.
details
.
status
.
text
}
`
;
},
},
template
:
`
<td class="commit-link">
<a
:class="cssClasses"
:href="detailsPath"
v-html="content">
</a>
</td>
`
,
});
})(
window
.
gl
||
(
window
.
gl
=
{}));
app/assets/javascripts/vue_pipelines_index/store.js
deleted
100644 → 0
View file @
bb1620aa
/* global gl, Flash */
/* eslint-disable no-param-reassign */
((
gl
)
=>
{
const
pageValues
=
(
headers
)
=>
{
const
normalized
=
gl
.
utils
.
normalizeHeaders
(
headers
);
const
paginationInfo
=
gl
.
utils
.
parseIntPagination
(
normalized
);
return
paginationInfo
;
};
gl
.
PipelineStore
=
class
{
fetchDataLoop
(
Vue
,
pageNum
,
url
,
apiScope
)
{
this
.
pageRequest
=
true
;
return
this
.
$http
.
get
(
`
${
url
}
?scope=
${
apiScope
}
&page=
${
pageNum
}
`
)
.
then
((
response
)
=>
{
const
pageInfo
=
pageValues
(
response
.
headers
);
this
.
pageInfo
=
Object
.
assign
({},
this
.
pageInfo
,
pageInfo
);
const
res
=
JSON
.
parse
(
response
.
body
);
this
.
count
=
Object
.
assign
({},
this
.
count
,
res
.
count
);
this
.
pipelines
=
Object
.
assign
([],
this
.
pipelines
,
res
.
pipelines
);
this
.
pageRequest
=
false
;
},
()
=>
{
this
.
pageRequest
=
false
;
return
new
Flash
(
'
An error occurred while fetching the pipelines, please reload the page again.
'
);
});
}
};
})(
window
.
gl
||
(
window
.
gl
=
{}));
app/assets/javascripts/
commit/pipelin
es/pipelines_store.js
→
app/assets/javascripts/
vue_pipelines_index/stor
es/pipelines_store.js
View file @
b0f2cbce
/* eslint-disable no-underscore-dangle*/
/**
* Pipelines' Store for commits view.
*
* Used to store the Pipelines rendered in the commit view in the pipelines table.
*/
require
(
'
../../vue_realtime_listener
'
);
class
PipelinesStore
{
import
'
../../vue_realtime_listener
'
;
export
default
class
PipelinesStore
{
constructor
()
{
this
.
state
=
{};
this
.
state
.
pipelines
=
[];
this
.
state
.
count
=
{};
this
.
state
.
pageInfo
=
{};
}
storePipelines
(
pipelines
=
[])
{
this
.
state
.
pipelines
=
pipelines
;
}
return
pipelines
;
storeCount
(
count
=
{})
{
this
.
state
.
count
=
count
;
}
storePagination
(
pagination
=
{})
{
let
paginationInfo
;
if
(
Object
.
keys
(
pagination
).
length
)
{
const
normalizedHeaders
=
gl
.
utils
.
normalizeHeaders
(
pagination
);
paginationInfo
=
gl
.
utils
.
parseIntPagination
(
normalizedHeaders
);
}
else
{
paginationInfo
=
pagination
;
}
this
.
state
.
pageInfo
=
paginationInfo
;
}
/**
* FIXME: Move this inside the component.
*
* Once the data is received we will start the time ago loops.
*
* Everytime a request is made like retry or cancel a pipeline, every 10 seconds we
* update the time to show how long as passed.
*
*/
sta
tic
sta
rtTimeAgoLoops
()
{
startTimeAgoLoops
()
{
const
startTimeLoops
=
()
=>
{
this
.
timeLoopInterval
=
setInterval
(()
=>
{
this
.
$children
[
0
].
$children
.
reduce
((
acc
,
component
)
=>
{
...
...
@@ -44,5 +59,3 @@ class PipelinesStore {
gl
.
VueRealtimeListener
(
removeIntervals
,
startIntervals
);
}
}
module
.
exports
=
PipelinesStore
;
app/assets/javascripts/vue_pipelines_index/time_ago.js
deleted
100644 → 0
View file @
bb1620aa
/* global Vue, gl */
/* eslint-disable no-param-reassign */
window
.
Vue
=
require
(
'
vue
'
);
require
(
'
../lib/utils/datetime_utility
'
);
const
iconTimerSvg
=
require
(
'
../../../views/shared/icons/_icon_timer.svg
'
);
((
gl
)
=>
{
gl
.
VueTimeAgo
=
Vue
.
extend
({
data
()
{
return
{
currentTime
:
new
Date
(),
iconTimerSvg
,
};
},
props
:
[
'
pipeline
'
],
computed
:
{
timeAgo
()
{
return
gl
.
utils
.
getTimeago
();
},
localTimeFinished
()
{
return
gl
.
utils
.
formatDate
(
this
.
pipeline
.
details
.
finished_at
);
},
timeStopped
()
{
const
changeTime
=
this
.
currentTime
;
const
options
=
{
weekday
:
'
long
'
,
year
:
'
numeric
'
,
month
:
'
short
'
,
day
:
'
numeric
'
,
};
options
.
timeZoneName
=
'
short
'
;
const
finished
=
this
.
pipeline
.
details
.
finished_at
;
if
(
!
finished
&&
changeTime
)
return
false
;
return
({
words
:
this
.
timeAgo
.
format
(
finished
)
});
},
duration
()
{
const
{
duration
}
=
this
.
pipeline
.
details
;
const
date
=
new
Date
(
duration
*
1000
);
let
hh
=
date
.
getUTCHours
();
let
mm
=
date
.
getUTCMinutes
();
let
ss
=
date
.
getSeconds
();
if
(
hh
<
10
)
hh
=
`0
${
hh
}
`
;
if
(
mm
<
10
)
mm
=
`0
${
mm
}
`
;
if
(
ss
<
10
)
ss
=
`0
${
ss
}
`
;
if
(
duration
!==
null
)
return
`
${
hh
}
:
${
mm
}
:
${
ss
}
`
;
return
false
;
},
},
methods
:
{
changeTime
()
{
this
.
currentTime
=
new
Date
();
},
},
template
:
`
<td class="pipelines-time-ago">
<p class="duration" v-if='duration'>
<span v-html="iconTimerSvg"></span>
{{duration}}
</p>
<p class="finished-at" v-if='timeStopped'>
<i class="fa fa-calendar"></i>
<time
data-toggle="tooltip"
data-placement="top"
data-container="body"
:data-original-title='localTimeFinished'>
{{timeStopped.words}}
</time>
</p>
</td>
`
,
});
})(
window
.
gl
||
(
window
.
gl
=
{}));
app/assets/javascripts/vue_shared/components/commit.js
View file @
b0f2cbce
/* global Vue */
window
.
Vue
=
require
(
'
vue
'
);
const
commitIconSvg
=
require
(
'
icons/_icon_commit.svg
'
);
(()
=>
{
window
.
gl
=
window
.
gl
||
{};
window
.
gl
.
CommitComponent
=
Vue
.
component
(
'
commit-component
'
,
{
props
:
{
/**
* Indicates the existance of a tag.
* Used to render the correct icon, if true will render `fa-tag` icon,
* if false will render `fa-code-fork` icon.
*/
tag
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
/**
* If provided is used to render the branch name and url.
* Should contain the following properties:
* name
* ref_url
*/
commitRef
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({}),
},
/**
* Used to link to the commit sha.
*/
commitUrl
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
/**
* Used to show the commit short sha that links to the commit url.
*/
shortSha
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
/**
* If provided shows the commit tile.
*/
title
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
/**
* If provided renders information about the author of the commit.
* When provided should include:
* `avatar_url` to render the avatar icon
* `web_url` to link to user profile
* `username` to render alt and title tags
*/
author
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({}),
},
import
commitIconSvg
from
'
icons/_icon_commit.svg
'
;
export
default
{
props
:
{
/**
* Indicates the existance of a tag.
* Used to render the correct icon, if true will render `fa-tag` icon,
* if false will render `fa-code-fork` icon.
*/
tag
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
computed
:
{
/**
* Used to verify if all the properties needed to render the commit
* ref section were provided.
*
* TODO: Improve this! Use lodash _.has when we have it.
*
* @returns {Boolean}
*/
hasCommitRef
()
{
return
this
.
commitRef
&&
this
.
commitRef
.
name
&&
this
.
commitRef
.
ref_url
;
},
/**
* Used to verify if all the properties needed to render the commit
* author section were provided.
*
* TODO: Improve this! Use lodash _.has when we have it.
*
* @returns {Boolean}
*/
hasAuthor
()
{
return
this
.
author
&&
this
.
author
.
avatar_url
&&
this
.
author
.
web_url
&&
this
.
author
.
username
;
},
/**
* If information about the author is provided will return a string
* to be rendered as the alt attribute of the img tag.
*
* @returns {String}
*/
userImageAltDescription
()
{
return
this
.
author
&&
this
.
author
.
username
?
`
${
this
.
author
.
username
}
's avatar`
:
null
;
},
/**
* If provided is used to render the branch name and url.
* Should contain the following properties:
* name
* ref_url
*/
commitRef
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({}),
},
data
()
{
return
{
commitIconSvg
};
/**
* Used to link to the commit sha.
*/
commitUrl
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
template
:
`
<div class="branch-commit">
<div v-if="hasCommitRef" class="icon-container">
<i v-if="tag" class="fa fa-tag"></i>
<i v-if="!tag" class="fa fa-code-fork"></i>
</div>
<a v-if="hasCommitRef"
class="monospace branch-name"
:href="commitRef.ref_url">
{{commitRef.name}}
</a>
<div v-html="commitIconSvg" class="commit-icon js-commit-icon"></div>
<a class="commit-id monospace"
:href="commitUrl">
{{shortSha}}
</a>
<p class="commit-title">
<span v-if="title">
<a v-if="hasAuthor"
class="avatar-image-container"
:href="author.web_url">
<img
class="avatar has-tooltip s20"
:src="author.avatar_url"
:alt="userImageAltDescription"
:title="author.username" />
</a>
<a class="commit-row-message"
:href="commitUrl">
{{title}}
</a>
</span>
<span v-else>
Cant find HEAD commit for this branch
</span>
</p>
/**
* Used to show the commit short sha that links to the commit url.
*/
shortSha
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
/**
* If provided shows the commit tile.
*/
title
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
/**
* If provided renders information about the author of the commit.
* When provided should include:
* `avatar_url` to render the avatar icon
* `web_url` to link to user profile
* `username` to render alt and title tags
*/
author
:
{
type
:
Object
,
required
:
false
,
default
:
()
=>
({}),
},
},
computed
:
{
/**
* Used to verify if all the properties needed to render the commit
* ref section were provided.
*
* TODO: Improve this! Use lodash _.has when we have it.
*
* @returns {Boolean}
*/
hasCommitRef
()
{
return
this
.
commitRef
&&
this
.
commitRef
.
name
&&
this
.
commitRef
.
ref_url
;
},
/**
* Used to verify if all the properties needed to render the commit
* author section were provided.
*
* TODO: Improve this! Use lodash _.has when we have it.
*
* @returns {Boolean}
*/
hasAuthor
()
{
return
this
.
author
&&
this
.
author
.
avatar_url
&&
this
.
author
.
web_url
&&
this
.
author
.
username
;
},
/**
* If information about the author is provided will return a string
* to be rendered as the alt attribute of the img tag.
*
* @returns {String}
*/
userImageAltDescription
()
{
return
this
.
author
&&
this
.
author
.
username
?
`
${
this
.
author
.
username
}
's avatar`
:
null
;
},
},
data
()
{
return
{
commitIconSvg
};
},
template
:
`
<div class="branch-commit">
<div v-if="hasCommitRef" class="icon-container">
<i v-if="tag" class="fa fa-tag"></i>
<i v-if="!tag" class="fa fa-code-fork"></i>
</div>
`
,
});
})();
<a v-if="hasCommitRef"
class="monospace branch-name"
:href="commitRef.ref_url">
{{commitRef.name}}
</a>
<div v-html="commitIconSvg" class="commit-icon js-commit-icon"></div>
<a class="commit-id monospace"
:href="commitUrl">
{{shortSha}}
</a>
<p class="commit-title">
<span v-if="title">
<a v-if="hasAuthor"
class="avatar-image-container"
:href="author.web_url">
<img
class="avatar has-tooltip s20"
:src="author.avatar_url"
:alt="userImageAltDescription"
:title="author.username" />
</a>
<a class="commit-row-message"
:href="commitUrl">
{{title}}
</a>
</span>
<span v-else>
Cant find HEAD commit for this branch
</span>
</p>
</div>
`
,
};
app/assets/javascripts/vue_shared/components/pipelines_table.js
View file @
b0f2cbce
/* eslint-disable no-param-reassign */
/* global Vue */
import
PipelinesTableRowComponent
from
'
./pipelines_table_row
'
;
require
(
'
./pipelines_table_row
'
);
/**
* Pipelines Table Component.
*
* Given an array of objects, renders a table.
*/
(()
=>
{
window
.
gl
=
window
.
gl
||
{};
gl
.
pipelines
=
gl
.
pipelines
||
{};
gl
.
pipelines
.
PipelinesTableComponent
=
Vue
.
component
(
'
pipelines-table-component
'
,
{
props
:
{
pipelines
:
{
type
:
Array
,
required
:
true
,
default
:
()
=>
([]),
},
export
default
{
props
:
{
pipelines
:
{
type
:
Array
,
required
:
true
,
default
:
()
=>
([]),
},
components
:
{
'
pipelines-table-row-component
'
:
gl
.
pipelines
.
PipelinesTableRowComponent
,
service
:
{
type
:
Object
,
required
:
true
,
},
},
components
:
{
'
pipelines-table-row-component
'
:
PipelinesTableRowComponent
,
},
template
:
`
<table class="table ci-table">
<thead>
<tr>
<th class="js-pipeline-status pipeline-status">Status</th>
<th class="js-pipeline-info pipeline-info">Pipeline</th>
<th class="js-pipeline-commit pipeline-commit">Commit</th>
<th class="js-pipeline-stages pipeline-stages">Stages</th>
<th class="js-pipeline-date pipeline-date"></th>
<th class="js-pipeline-actions pipeline-actions"></th>
</tr>
</thead>
<tbody>
<template v-for="model in pipelines"
v-bind:model="model">
<tr is="pipelines-table-row-component"
:pipeline="model"></tr>
</template
>
</t
body
>
</t
able
>
`
,
});
}
)()
;
template
:
`
<table class="table ci-table">
<thead>
<tr>
<th class="js-pipeline-status pipeline-status">Status</th>
<th class="js-pipeline-info pipeline-info">Pipeline</th>
<th class="js-pipeline-commit pipeline-commit">Commit</th>
<th class="js-pipeline-stages pipeline-stages">Stages</th>
<th class="js-pipeline-date pipeline-date"></th>
<th class="js-pipeline-actions pipeline-actions"></th>
</tr>
</thead>
<tbody>
<template v-for="model in pipelines"
v-bind:model="model">
<tr is="pipelines-table-row-component"
:pipeline="model"
:service="service"></tr
>
</t
emplate
>
</t
body
>
</table>
`
,
};
app/assets/javascripts/vue_shared/components/pipelines_table_row.js
View file @
b0f2cbce
/* eslint-disable no-param-reassign */
/* global Vue */
require
(
'
../../vue_pipelines_index/status
'
);
require
(
'
../../vue_pipelines_index/pipeline_url
'
);
require
(
'
../../vue_pipelines_index/stage
'
);
require
(
'
../../vue_pipelines_index/pipeline_actions
'
);
require
(
'
../../vue_pipelines_index/time_ago
'
);
require
(
'
./commit
'
);
import
AsyncButtonComponent
from
'
../../vue_pipelines_index/components/async_button
'
;
import
PipelinesActionsComponent
from
'
../../vue_pipelines_index/components/pipelines_actions
'
;
import
PipelinesArtifactsComponent
from
'
../../vue_pipelines_index/components/pipelines_artifacts
'
;
import
PipelinesStatusComponent
from
'
../../vue_pipelines_index/components/status
'
;
import
PipelinesStageComponent
from
'
../../vue_pipelines_index/components/stage
'
;
import
PipelinesUrlComponent
from
'
../../vue_pipelines_index/components/pipeline_url
'
;
import
PipelinesTimeagoComponent
from
'
../../vue_pipelines_index/components/time_ago
'
;
import
CommitComponent
from
'
./commit
'
;
/**
* Pipeline table row.
*
* Given the received object renders a table row in the pipelines' table.
*/
(()
=>
{
window
.
gl
=
window
.
gl
||
{};
gl
.
pipelines
=
gl
.
pipelines
||
{};
gl
.
pipelines
.
PipelinesTableRowComponent
=
Vue
.
component
(
'
pipelines-table-row-component
'
,
{
props
:
{
pipeline
:
{
type
:
Object
,
required
:
true
,
default
:
()
=>
({}),
},
export
default
{
props
:
{
pipeline
:
{
type
:
Object
,
required
:
true
,
},
service
:
{
type
:
Object
,
required
:
true
,
},
},
components
:
{
'
async-button-component
'
:
AsyncButtonComponent
,
'
pipelines-actions-component
'
:
PipelinesActionsComponent
,
'
pipelines-artifacts-component
'
:
PipelinesArtifactsComponent
,
'
commit-component
'
:
CommitComponent
,
'
dropdown-stage
'
:
PipelinesStageComponent
,
'
pipeline-url
'
:
PipelinesUrlComponent
,
'
status-scope
'
:
PipelinesStatusComponent
,
'
time-ago
'
:
PipelinesTimeagoComponent
,
},
computed
:
{
/**
* If provided, returns the commit tag.
* Needed to render the commit component column.
*
* This field needs a lot of verification, because of different possible cases:
*
* 1. person who is an author of a commit might be a GitLab user
* 2. if person who is an author of a commit is a GitLab user he/she can have a GitLab avatar
* 3. If GitLab user does not have avatar he/she might have a Gravatar
* 4. If committer is not a GitLab User he/she can have a Gravatar
* 5. We do not have consistent API object in this case
* 6. We should improve API and the code
*
* @returns {Object|Undefined}
*/
commitAuthor
()
{
let
commitAuthorInformation
;
// 1. person who is an author of a commit might be a GitLab user
if
(
this
.
pipeline
&&
this
.
pipeline
.
commit
&&
this
.
pipeline
.
commit
.
author
)
{
// 2. if person who is an author of a commit is a GitLab user
// he/she can have a GitLab avatar
if
(
this
.
pipeline
.
commit
.
author
.
avatar_url
)
{
commitAuthorInformation
=
this
.
pipeline
.
commit
.
author
;
// 3. If GitLab user does not have avatar he/she might have a Gravatar
}
else
if
(
this
.
pipeline
.
commit
.
author_gravatar_url
)
{
commitAuthorInformation
=
Object
.
assign
({},
this
.
pipeline
.
commit
.
author
,
{
avatar_url
:
this
.
pipeline
.
commit
.
author_gravatar_url
,
});
}
}
// 4. If committer is not a GitLab User he/she can have a Gravatar
if
(
this
.
pipeline
&&
this
.
pipeline
.
commit
)
{
commitAuthorInformation
=
{
avatar_url
:
this
.
pipeline
.
commit
.
author_gravatar_url
,
web_url
:
`mailto:
${
this
.
pipeline
.
commit
.
author_email
}
`
,
username
:
this
.
pipeline
.
commit
.
author_name
,
};
}
return
commitAuthorInformation
;
},
components
:
{
'
commit-component
'
:
gl
.
CommitComponent
,
'
pipeline-actions
'
:
gl
.
VuePipelineActions
,
'
dropdown-stage
'
:
gl
.
VueStage
,
'
pipeline-url
'
:
gl
.
VuePipelineUrl
,
'
status-scope
'
:
gl
.
VueStatusScope
,
'
time-ago
'
:
gl
.
VueTimeAgo
,
/**
* If provided, returns the commit tag.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitTag
()
{
if
(
this
.
pipeline
.
ref
&&
this
.
pipeline
.
ref
.
tag
)
{
return
this
.
pipeline
.
ref
.
tag
;
}
return
undefined
;
},
computed
:
{
/**
* If provided, returns the commit tag.
* Needed to render the commit component column.
*
* This field needs a lot of verification, because of different possible cases:
*
* 1. person who is an author of a commit might be a GitLab user
* 2. if person who is an author of a commit is a GitLab user he/she can have a GitLab avatar
* 3. If GitLab user does not have avatar he/she might have a Gravatar
* 4. If committer is not a GitLab User he/she can have a Gravatar
* 5. We do not have consistent API object in this case
* 6. We should improve API and the code
*
* @returns {Object|Undefined}
*/
commitAuthor
()
{
let
commitAuthorInformation
;
// 1. person who is an author of a commit might be a GitLab user
if
(
this
.
pipeline
&&
this
.
pipeline
.
commit
&&
this
.
pipeline
.
commit
.
author
)
{
// 2. if person who is an author of a commit is a GitLab user
// he/she can have a GitLab avatar
if
(
this
.
pipeline
.
commit
.
author
.
avatar_url
)
{
commitAuthorInformation
=
this
.
pipeline
.
commit
.
author
;
// 3. If GitLab user does not have avatar he/she might have a Gravatar
}
else
if
(
this
.
pipeline
.
commit
.
author_gravatar_url
)
{
commitAuthorInformation
=
Object
.
assign
({},
this
.
pipeline
.
commit
.
author
,
{
avatar_url
:
this
.
pipeline
.
commit
.
author_gravatar_url
,
});
/**
* If provided, returns the commit ref.
* Needed to render the commit component column.
*
* Matches `path` prop sent in the API to `ref_url` prop needed
* in the commit component.
*
* @returns {Object|Undefined}
*/
commitRef
()
{
if
(
this
.
pipeline
.
ref
)
{
return
Object
.
keys
(
this
.
pipeline
.
ref
).
reduce
((
accumulator
,
prop
)
=>
{
if
(
prop
===
'
path
'
)
{
accumulator
.
ref_url
=
this
.
pipeline
.
ref
[
prop
];
}
else
{
accumulator
[
prop
]
=
this
.
pipeline
.
ref
[
prop
];
}
}
return
accumulator
;
},
{});
}
// 4. If committer is not a GitLab User he/she can have a Gravatar
if
(
this
.
pipeline
&&
this
.
pipeline
.
commit
)
{
commitAuthorInformation
=
{
avatar_url
:
this
.
pipeline
.
commit
.
author_gravatar_url
,
web_url
:
`mailto:
${
this
.
pipeline
.
commit
.
author_email
}
`
,
username
:
this
.
pipeline
.
commit
.
author_name
,
};
}
return
undefined
;
},
return
commitAuthorInformation
;
},
/**
* If provided, returns the commit tag.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitTag
()
{
if
(
this
.
pipeline
.
ref
&&
this
.
pipeline
.
ref
.
tag
)
{
return
this
.
pipeline
.
ref
.
tag
;
}
return
undefined
;
},
/**
* If provided, returns the commit ref.
* Needed to render the commit component column.
*
* Matches `path` prop sent in the API to `ref_url` prop needed
* in the commit component.
*
* @returns {Object|Undefined}
*/
commitRef
()
{
if
(
this
.
pipeline
.
ref
)
{
return
Object
.
keys
(
this
.
pipeline
.
ref
).
reduce
((
accumulator
,
prop
)
=>
{
if
(
prop
===
'
path
'
)
{
accumulator
.
ref_url
=
this
.
pipeline
.
ref
[
prop
];
}
else
{
accumulator
[
prop
]
=
this
.
pipeline
.
ref
[
prop
];
}
return
accumulator
;
},
{});
}
/**
* If provided, returns the commit url.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitUrl
()
{
if
(
this
.
pipeline
.
commit
&&
this
.
pipeline
.
commit
.
commit_path
)
{
return
this
.
pipeline
.
commit
.
commit_path
;
}
return
undefined
;
},
return
undefined
;
},
/**
* If provided, returns the commit url.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitUrl
()
{
if
(
this
.
pipeline
.
commit
&&
this
.
pipeline
.
commit
.
commit_path
)
{
return
this
.
pipeline
.
commit
.
commit_path
;
}
return
undefined
;
},
/**
* If provided, returns the commit short sha.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitShortSha
()
{
if
(
this
.
pipeline
.
commit
&&
this
.
pipeline
.
commit
.
short_id
)
{
return
this
.
pipeline
.
commit
.
short_id
;
}
return
undefined
;
},
/**
* If provided, returns the commit title.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitTitle
()
{
if
(
this
.
pipeline
.
commit
&&
this
.
pipeline
.
commit
.
title
)
{
return
this
.
pipeline
.
commit
.
title
;
}
return
undefined
;
},
/**
* If provided, returns the commit short sha.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitShortSha
()
{
if
(
this
.
pipeline
.
commit
&&
this
.
pipeline
.
commit
.
short_id
)
{
return
this
.
pipeline
.
commit
.
short_id
;
}
return
undefined
;
},
template
:
`
<tr class="commit">
<status-scope :pipeline="pipeline"/>
<pipeline-url :pipeline="pipeline"></pipeline-url>
<td>
<commit-component
:tag="commitTag"
:commit-ref="commitRef"
:commit-url="commitUrl"
:short-sha="commitShortSha"
:title="commitTitle"
:author="commitAuthor"/>
</td>
<td class="stage-cell">
<div class="stage-container dropdown js-mini-pipeline-graph"
v-if="pipeline.details.stages.length > 0"
v-for="stage in pipeline.details.stages">
<dropdown-stage :stage="stage"/>
</div>
</td>
<time-ago :pipeline="pipeline"/>
<pipeline-actions :pipeline="pipeline" />
</tr>
`
,
});
})();
/**
* If provided, returns the commit title.
* Needed to render the commit component column.
*
* @returns {String|Undefined}
*/
commitTitle
()
{
if
(
this
.
pipeline
.
commit
&&
this
.
pipeline
.
commit
.
title
)
{
return
this
.
pipeline
.
commit
.
title
;
}
return
undefined
;
},
},
template
:
`
<tr class="commit">
<status-scope :pipeline="pipeline"/>
<pipeline-url :pipeline="pipeline"></pipeline-url>
<td>
<commit-component
:tag="commitTag"
:commit-ref="commitRef"
:commit-url="commitUrl"
:short-sha="commitShortSha"
:title="commitTitle"
:author="commitAuthor"/>
</td>
<td class="stage-cell">
<div class="stage-container dropdown js-mini-pipeline-graph"
v-if="pipeline.details.stages.length > 0"
v-for="stage in pipeline.details.stages">
<dropdown-stage :stage="stage"/>
</div>
</td>
<time-ago :pipeline="pipeline"/>
<td class="pipeline-actions">
<div class="pull-right btn-group">
<pipelines-actions-component
v-if="pipeline.details.manual_actions.length"
:actions="pipeline.details.manual_actions"
:service="service" />
<pipelines-artifacts-component
v-if="pipeline.details.artifacts.length"
:artifacts="pipeline.details.artifacts" />
<async-button-component
v-if="pipeline.flags.retryable"
:service="service"
:endpoint="pipeline.retry_path"
css-class="js-pipelines-retry-button btn-default btn-retry"
title="Retry"
icon="repeat" />
<async-button-component
v-if="pipeline.flags.cancelable"
:service="service"
:endpoint="pipeline.cancel_path"
css-class="js-pipelines-cancel-button btn-remove"
title="Cancel"
icon="remove"
confirm-action-message="Are you sure you want to cancel this pipeline?" />
</div>
</td>
</tr>
`
,
};
app/assets/javascripts/vue_shared/components/table_pagination.js
View file @
b0f2cbce
/* global Vue, gl */
/* eslint-disable no-param-reassign, no-plusplus */
window
.
Vue
=
require
(
'
vue
'
);
((
gl
)
=>
{
const
PAGINATION_UI_BUTTON_LIMIT
=
4
;
const
UI_LIMIT
=
6
;
const
SPREAD
=
'
...
'
;
const
PREV
=
'
Prev
'
;
const
NEXT
=
'
Next
'
;
const
FIRST
=
'
<< First
'
;
const
LAST
=
'
Last >>
'
;
gl
.
VueGlPagination
=
Vue
.
extend
({
props
:
{
// TODO: Consider refactoring in light of turbolinks removal.
/**
This function will take the information given by the pagination component
Here is an example `change` method:
change(pagenum) {
gl.utils.visitUrl(`?page=${pagenum}`);
},
*/
change
:
{
type
:
Function
,
required
:
true
,
const
PAGINATION_UI_BUTTON_LIMIT
=
4
;
const
UI_LIMIT
=
6
;
const
SPREAD
=
'
...
'
;
const
PREV
=
'
Prev
'
;
const
NEXT
=
'
Next
'
;
const
FIRST
=
'
<< First
'
;
const
LAST
=
'
Last >>
'
;
export
default
{
props
:
{
/**
This function will take the information given by the pagination component
Here is an example `change` method:
change(pagenum) {
gl.utils.visitUrl(`?page=${pagenum}`);
},
*/
change
:
{
type
:
Function
,
required
:
true
,
},
/**
pageInfo will come from the headers of the API call
in the `.then` clause of the VueResource API call
there should be a function that contructs the pageInfo for this component
This is an example:
const pageInfo = headers => ({
perPage: +headers['X-Per-Page'],
page: +headers['X-Page'],
total: +headers['X-Total'],
totalPages: +headers['X-Total-Pages'],
nextPage: +headers['X-Next-Page'],
previousPage: +headers['X-Prev-Page'],
});
*/
pageInfo
:
{
type
:
Object
,
required
:
true
,
},
/**
pageInfo will come from the headers of the API call
in the `.then` clause of the VueResource API call
there should be a function that contructs the pageInfo for this component
This is an example:
const pageInfo = headers => ({
perPage: +headers['X-Per-Page'],
page: +headers['X-Page'],
total: +headers['X-Total'],
totalPages: +headers['X-Total-Pages'],
nextPage: +headers['X-Next-Page'],
previousPage: +headers['X-Prev-Page'],
});
*/
pageInfo
:
{
type
:
Object
,
required
:
true
,
},
methods
:
{
changePage
(
e
)
{
const
text
=
e
.
target
.
innerText
;
const
{
totalPages
,
nextPage
,
previousPage
}
=
this
.
pageInfo
;
switch
(
text
)
{
case
SPREAD
:
break
;
case
LAST
:
this
.
change
(
totalPages
);
break
;
case
NEXT
:
this
.
change
(
nextPage
);
break
;
case
PREV
:
this
.
change
(
previousPage
);
break
;
case
FIRST
:
this
.
change
(
1
);
break
;
default
:
this
.
change
(
+
text
);
break
;
}
}
,
},
methods
:
{
changePage
(
e
)
{
const
text
=
e
.
target
.
innerText
;
const
{
totalPages
,
nextPage
,
previousPage
}
=
this
.
pageInfo
;
switch
(
text
)
{
case
SPREAD
:
break
;
case
LAST
:
this
.
change
(
totalPages
)
;
break
;
case
NEXT
:
this
.
change
(
nextPage
)
;
break
;
case
PREV
:
this
.
change
(
previousPage
)
;
break
;
case
FIRST
:
this
.
change
(
1
)
;
break
;
default
:
this
.
change
(
+
text
)
;
break
;
}
},
computed
:
{
prev
()
{
return
this
.
pageInfo
.
previousPage
;
},
next
()
{
return
this
.
pageInfo
.
nextPage
;
},
getItems
()
{
const
total
=
this
.
pageInfo
.
totalPages
;
const
page
=
this
.
pageInfo
.
page
;
const
items
=
[];
},
computed
:
{
prev
()
{
return
this
.
pageInfo
.
previousPage
;
},
next
()
{
return
this
.
pageInfo
.
nextPage
;
},
getItems
()
{
const
total
=
this
.
pageInfo
.
totalPages
;
const
page
=
this
.
pageInfo
.
page
;
const
items
=
[];
if
(
page
>
1
)
items
.
push
({
title
:
FIRST
});
if
(
page
>
1
)
items
.
push
({
title
:
FIRST
});
if
(
page
>
1
)
{
items
.
push
({
title
:
PREV
,
prev
:
true
});
}
else
{
items
.
push
({
title
:
PREV
,
disabled
:
true
,
prev
:
true
});
}
if
(
page
>
1
)
{
items
.
push
({
title
:
PREV
,
prev
:
true
});
}
else
{
items
.
push
({
title
:
PREV
,
disabled
:
true
,
prev
:
true
});
}
if
(
page
>
UI_LIMIT
)
items
.
push
({
title
:
SPREAD
,
separator
:
true
});
if
(
page
>
UI_LIMIT
)
items
.
push
({
title
:
SPREAD
,
separator
:
true
});
const
start
=
Math
.
max
(
page
-
PAGINATION_UI_BUTTON_LIMIT
,
1
);
const
end
=
Math
.
min
(
page
+
PAGINATION_UI_BUTTON_LIMIT
,
total
);
const
start
=
Math
.
max
(
page
-
PAGINATION_UI_BUTTON_LIMIT
,
1
);
const
end
=
Math
.
min
(
page
+
PAGINATION_UI_BUTTON_LIMIT
,
total
);
for
(
let
i
=
start
;
i
<=
end
;
i
++
)
{
const
isActive
=
i
===
page
;
items
.
push
({
title
:
i
,
active
:
isActive
,
page
:
true
});
}
for
(
let
i
=
start
;
i
<=
end
;
i
+=
1
)
{
const
isActive
=
i
===
page
;
items
.
push
({
title
:
i
,
active
:
isActive
,
page
:
true
});
}
if
(
total
-
page
>
PAGINATION_UI_BUTTON_LIMIT
)
{
items
.
push
({
title
:
SPREAD
,
separator
:
true
,
page
:
true
});
}
if
(
total
-
page
>
PAGINATION_UI_BUTTON_LIMIT
)
{
items
.
push
({
title
:
SPREAD
,
separator
:
true
,
page
:
true
});
}
if
(
page
===
total
)
{
items
.
push
({
title
:
NEXT
,
disabled
:
true
,
next
:
true
});
}
else
if
(
total
-
page
>=
1
)
{
items
.
push
({
title
:
NEXT
,
next
:
true
});
}
if
(
page
===
total
)
{
items
.
push
({
title
:
NEXT
,
disabled
:
true
,
next
:
true
});
}
else
if
(
total
-
page
>=
1
)
{
items
.
push
({
title
:
NEXT
,
next
:
true
});
}
if
(
total
-
page
>=
1
)
items
.
push
({
title
:
LAST
,
last
:
true
});
if
(
total
-
page
>=
1
)
items
.
push
({
title
:
LAST
,
last
:
true
});
return
items
;
},
return
items
;
},
template
:
`
<div class="gl-pagination">
<ul class="pagination clearfix
">
<li v-for='item in getItems'
:class='{
page: item.page,
prev: item.prev
,
next: item.next
,
separator: item.separator
,
active: item.active
,
disabled: item.disabled
}'
>
<a @click="changePage($event)">{{item.title}}</a
>
<
/li
>
</
ul
>
</
div
>
`
,
});
}
)(
window
.
gl
||
(
window
.
gl
=
{}))
;
},
template
:
`
<div class="gl-pagination
">
<ul class="pagination clearfix">
<li v-for='item in getItems'
:class='{
page: item.page
,
prev: item.prev
,
next: item.next
,
separator: item.separator
,
active: item.active,
disabled: item.disabled
}'
>
<
a @click="changePage($event)">{{item.title}}</a
>
</
li
>
</
ul
>
</div>
`
,
};
app/assets/javascripts/vue_shared/vue_resource_interceptor.js
View file @
b0f2cbce
/* eslint-disable func-names, prefer-arrow-callback, no-unused-vars,
no-param-reassign, no-plusplus */
/* global Vue */
/* eslint-disable no-param-reassign, no-plusplus */
import
Vue
from
'
vue
'
;
import
VueResource
from
'
vue-resource
'
;
Vue
.
use
(
VueResource
);
Vue
.
http
.
interceptors
.
push
((
request
,
next
)
=>
{
Vue
.
activeResources
=
Vue
.
activeResources
?
Vue
.
activeResources
+
1
:
1
;
next
((
response
)
=>
{
next
(()
=>
{
Vue
.
activeResources
--
;
});
});
...
...
app/assets/stylesheets/pages/pipelines.scss
View file @
b0f2cbce
...
...
@@ -72,11 +72,6 @@
color
:
$gl-text-color-secondary
;
font-size
:
14px
;
}
svg
,
.fa
{
margin-right
:
0
;
}
}
.btn-group
{
...
...
@@ -921,3 +916,22 @@
}
}
}
/**
* Play button with icon in dropdowns
*/
.ci-table
.no-btn
{
border
:
none
;
background
:
none
;
outline
:
none
;
width
:
100%
;
text-align
:
left
;
.icon-play
{
position
:
relative
;
top
:
2px
;
margin-right
:
5px
;
height
:
13px
;
width
:
12px
;
}
}
changelogs/unreleased/fl-remove-ujs-pipelines.yml
0 → 100644
View file @
b0f2cbce
---
title
:
'
Removes
UJS
from
pipelines
tables'
merge_request
:
9929
author
:
spec/features/merge_requests/created_from_fork_spec.rb
View file @
b0f2cbce
...
...
@@ -60,9 +60,6 @@ feature 'Merge request created from fork' do
expect
(
page
).
to
have_content
pipeline
.
status
expect
(
page
).
to
have_content
pipeline
.
id
end
expect
(
page
.
find
(
'a.btn-remove'
)[
:href
])
.
to
include
fork_project
.
path_with_namespace
end
end
...
...
spec/features/projects/pipelines/pipelines_spec.rb
View file @
b0f2cbce
...
...
@@ -99,15 +99,18 @@ describe 'Pipelines', :feature, :js do
end
it
'indicates that pipeline can be canceled'
do
expect
(
page
).
to
have_
link
(
'Cancel
'
)
expect
(
page
).
to
have_
selector
(
'.js-pipelines-cancel-button
'
)
expect
(
page
).
to
have_selector
(
'.ci-running'
)
end
context
'when canceling'
do
before
{
click_link
(
'Cancel'
)
}
before
do
find
(
'.js-pipelines-cancel-button'
).
click
wait_for_vue_resource
end
it
'indicated that pipelines was canceled'
do
expect
(
page
).
not_to
have_
link
(
'Cancel
'
)
expect
(
page
).
not_to
have_
selector
(
'.js-pipelines-cancel-button
'
)
expect
(
page
).
to
have_selector
(
'.ci-canceled'
)
end
end
...
...
@@ -126,15 +129,18 @@ describe 'Pipelines', :feature, :js do
end
it
'indicates that pipeline can be retried'
do
expect
(
page
).
to
have_
link
(
'Retry
'
)
expect
(
page
).
to
have_
selector
(
'.js-pipelines-retry-button
'
)
expect
(
page
).
to
have_selector
(
'.ci-failed'
)
end
context
'when retrying'
do
before
{
click_link
(
'Retry'
)
}
before
do
find
(
'.js-pipelines-retry-button'
).
click
wait_for_vue_resource
end
it
'shows running pipeline that is not retryable'
do
expect
(
page
).
not_to
have_
link
(
'Retry
'
)
expect
(
page
).
not_to
have_
selector
(
'.js-pipelines-retry-button
'
)
expect
(
page
).
to
have_selector
(
'.ci-running'
)
end
end
...
...
@@ -176,17 +182,17 @@ describe 'Pipelines', :feature, :js do
it
'has link to the manual action'
do
find
(
'.js-pipeline-dropdown-manual-actions'
).
click
expect
(
page
).
to
have_
link
(
'manual build'
)
expect
(
page
).
to
have_
button
(
'manual build'
)
end
context
'when manual action was played'
do
before
do
find
(
'.js-pipeline-dropdown-manual-actions'
).
click
click_
link
(
'manual build'
)
click_
button
(
'manual build'
)
end
it
'enqueues manual action job'
do
expect
(
manual
.
reload
).
to
be_pending
expect
(
page
).
to
have_selector
(
'.js-pipeline-dropdown-manual-actions:disabled'
)
end
end
end
...
...
@@ -203,7 +209,7 @@ describe 'Pipelines', :feature, :js do
before
{
visit_project_pipelines
}
it
'is cancelable'
do
expect
(
page
).
to
have_
link
(
'Cancel
'
)
expect
(
page
).
to
have_
selector
(
'.js-pipelines-cancel-button
'
)
end
it
'has pipeline running'
do
...
...
@@ -211,10 +217,10 @@ describe 'Pipelines', :feature, :js do
end
context
'when canceling'
do
before
{
click_link
(
'Cancel
'
)
}
before
{
find
(
'.js-pipelines-cancel-button'
).
trigger
(
'click
'
)
}
it
'indicates that pipeline was canceled'
do
expect
(
page
).
not_to
have_
link
(
'Cancel
'
)
expect
(
page
).
not_to
have_
selector
(
'.js-pipelines-cancel-button
'
)
expect
(
page
).
to
have_selector
(
'.ci-canceled'
)
end
end
...
...
@@ -233,7 +239,7 @@ describe 'Pipelines', :feature, :js do
end
it
'is not retryable'
do
expect
(
page
).
not_to
have_
link
(
'Retry
'
)
expect
(
page
).
not_to
have_
selector
(
'.js-pipelines-retry-button
'
)
end
it
'has failed pipeline'
do
...
...
spec/javascripts/commit/pipelines/mock_data.js
View file @
b0f2cbce
/* eslint-disable no-unused-vars */
const
pipeline
=
{
export
default
{
id
:
73
,
user
:
{
name
:
'
Administrator
'
,
...
...
@@ -88,5 +87,3 @@ const pipeline = {
created_at
:
'
2017-01-16T17:13:59.800Z
'
,
updated_at
:
'
2017-01-25T00:00:17.132Z
'
,
};
module
.
exports
=
pipeline
;
spec/javascripts/commit/pipelines/pipelines_spec.js
View file @
b0f2cbce
/* global pipeline, Vue */
require
(
'
~/flash
'
);
require
(
'
~/commit/pipelines/pipelines_store
'
);
require
(
'
~/commit/pipelines/pipelines_service
'
);
require
(
'
~/commit/pipelines/pipelines_table
'
);
require
(
'
~/vue_shared/vue_resource_interceptor
'
);
const
pipeline
=
require
(
'
./mock_data
'
);
import
Vue
from
'
vue
'
;
import
PipelinesTable
from
'
~/commit/pipelines/pipelines_table
'
;
import
pipeline
from
'
./mock_data
'
;
describe
(
'
Pipelines table in Commits and Merge requests
'
,
()
=>
{
preloadFixtures
(
'
static/pipelines_table.html.raw
'
);
...
...
@@ -33,7 +28,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
});
it
(
'
should render the empty state
'
,
(
done
)
=>
{
const
component
=
new
gl
.
commits
.
pipelines
.
PipelinesTableView
({
const
component
=
new
PipelinesTable
({
el
:
document
.
querySelector
(
'
#commit-pipeline-table-view
'
),
});
...
...
@@ -62,7 +57,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
});
it
(
'
should render a table with the received pipelines
'
,
(
done
)
=>
{
const
component
=
new
gl
.
commits
.
pipelines
.
PipelinesTableView
({
const
component
=
new
PipelinesTable
({
el
:
document
.
querySelector
(
'
#commit-pipeline-table-view
'
),
});
...
...
@@ -92,7 +87,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
});
it
(
'
should render empty state
'
,
(
done
)
=>
{
const
component
=
new
gl
.
commits
.
pipelines
.
PipelinesTableView
({
const
component
=
new
PipelinesTable
({
el
:
document
.
querySelector
(
'
#commit-pipeline-table-view
'
),
});
...
...
spec/javascripts/commit/pipelines/pipelines_store_spec.js
deleted
100644 → 0
View file @
bb1620aa
const
PipelinesStore
=
require
(
'
~/commit/pipelines/pipelines_store
'
);
describe
(
'
Store
'
,
()
=>
{
let
store
;
beforeEach
(()
=>
{
store
=
new
PipelinesStore
();
});
// unregister intervals and event handlers
afterEach
(()
=>
gl
.
VueRealtimeListener
.
reset
());
it
(
'
should start with a blank state
'
,
()
=>
{
expect
(
store
.
state
.
pipelines
.
length
).
toBe
(
0
);
});
it
(
'
should store an array of pipelines
'
,
()
=>
{
const
pipelines
=
[
{
id
:
'
1
'
,
name
:
'
pipeline
'
,
},
{
id
:
'
2
'
,
name
:
'
pipeline_2
'
,
},
];
store
.
storePipelines
(
pipelines
);
expect
(
store
.
state
.
pipelines
.
length
).
toBe
(
pipelines
.
length
);
});
});
spec/javascripts/vue_pipelines_index/async_button_spec.js
0 → 100644
View file @
b0f2cbce
import
Vue
from
'
vue
'
;
import
asyncButtonComp
from
'
~/vue_pipelines_index/components/async_button
'
;
describe
(
'
Pipelines Async Button
'
,
()
=>
{
let
component
;
let
spy
;
let
AsyncButtonComponent
;
beforeEach
(()
=>
{
AsyncButtonComponent
=
Vue
.
extend
(
asyncButtonComp
);
spy
=
jasmine
.
createSpy
(
'
spy
'
).
and
.
returnValue
(
Promise
.
resolve
());
component
=
new
AsyncButtonComponent
({
propsData
:
{
endpoint
:
'
/foo
'
,
title
:
'
Foo
'
,
icon
:
'
fa fa-foo
'
,
cssClass
:
'
bar
'
,
service
:
{
postAction
:
spy
,
},
},
}).
$mount
();
});
it
(
'
should render a button
'
,
()
=>
{
expect
(
component
.
$el
.
tagName
).
toEqual
(
'
BUTTON
'
);
});
it
(
'
should render the provided icon
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
i
'
).
getAttribute
(
'
class
'
)).
toContain
(
'
fa fa-foo
'
);
});
it
(
'
should render the provided title
'
,
()
=>
{
expect
(
component
.
$el
.
getAttribute
(
'
title
'
)).
toContain
(
'
Foo
'
);
expect
(
component
.
$el
.
getAttribute
(
'
aria-label
'
)).
toContain
(
'
Foo
'
);
});
it
(
'
should render the provided cssClass
'
,
()
=>
{
expect
(
component
.
$el
.
getAttribute
(
'
class
'
)).
toContain
(
'
bar
'
);
});
it
(
'
should call the service when it is clicked with the provided endpoint
'
,
()
=>
{
component
.
$el
.
click
();
expect
(
spy
).
toHaveBeenCalledWith
(
'
/foo
'
);
});
it
(
'
should hide loading if request fails
'
,
()
=>
{
spy
=
jasmine
.
createSpy
(
'
spy
'
).
and
.
returnValue
(
Promise
.
reject
());
component
=
new
AsyncButtonComponent
({
propsData
:
{
endpoint
:
'
/foo
'
,
title
:
'
Foo
'
,
icon
:
'
fa fa-foo
'
,
cssClass
:
'
bar
'
,
dataAttributes
:
{
'
data-foo
'
:
'
foo
'
,
},
service
:
{
postAction
:
spy
,
},
},
}).
$mount
();
component
.
$el
.
click
();
expect
(
component
.
$el
.
querySelector
(
'
.fa-spinner
'
)).
toBe
(
null
);
});
describe
(
'
With confirm dialog
'
,
()
=>
{
it
(
'
should call the service when confimation is positive
'
,
()
=>
{
spyOn
(
window
,
'
confirm
'
).
and
.
returnValue
(
true
);
spy
=
jasmine
.
createSpy
(
'
spy
'
).
and
.
returnValue
(
Promise
.
resolve
());
component
=
new
AsyncButtonComponent
({
propsData
:
{
endpoint
:
'
/foo
'
,
title
:
'
Foo
'
,
icon
:
'
fa fa-foo
'
,
cssClass
:
'
bar
'
,
service
:
{
postAction
:
spy
,
},
confirmActionMessage
:
'
bar
'
,
},
}).
$mount
();
component
.
$el
.
click
();
expect
(
spy
).
toHaveBeenCalledWith
(
'
/foo
'
);
});
});
});
spec/javascripts/vue_pipelines_index/pipeline_url_spec.js
0 → 100644
View file @
b0f2cbce
import
Vue
from
'
vue
'
;
import
pipelineUrlComp
from
'
~/vue_pipelines_index/components/pipeline_url
'
;
describe
(
'
Pipeline Url Component
'
,
()
=>
{
let
PipelineUrlComponent
;
beforeEach
(()
=>
{
PipelineUrlComponent
=
Vue
.
extend
(
pipelineUrlComp
);
});
it
(
'
should render a table cell
'
,
()
=>
{
const
component
=
new
PipelineUrlComponent
({
propsData
:
{
pipeline
:
{
id
:
1
,
path
:
'
foo
'
,
flags
:
{},
},
},
}).
$mount
();
expect
(
component
.
$el
.
tagName
).
toEqual
(
'
TD
'
);
});
it
(
'
should render a link the provided path and id
'
,
()
=>
{
const
component
=
new
PipelineUrlComponent
({
propsData
:
{
pipeline
:
{
id
:
1
,
path
:
'
foo
'
,
flags
:
{},
},
},
}).
$mount
();
expect
(
component
.
$el
.
querySelector
(
'
.js-pipeline-url-link
'
).
getAttribute
(
'
href
'
)).
toEqual
(
'
foo
'
);
expect
(
component
.
$el
.
querySelector
(
'
.js-pipeline-url-link span
'
).
textContent
).
toEqual
(
'
#1
'
);
});
it
(
'
should render user information when a user is provided
'
,
()
=>
{
const
mockData
=
{
pipeline
:
{
id
:
1
,
path
:
'
foo
'
,
flags
:
{},
user
:
{
web_url
:
'
/
'
,
name
:
'
foo
'
,
avatar_url
:
'
/
'
,
},
},
};
const
component
=
new
PipelineUrlComponent
({
propsData
:
mockData
,
}).
$mount
();
const
image
=
component
.
$el
.
querySelector
(
'
.js-pipeline-url-user img
'
);
expect
(
component
.
$el
.
querySelector
(
'
.js-pipeline-url-user
'
).
getAttribute
(
'
href
'
),
).
toEqual
(
mockData
.
pipeline
.
user
.
web_url
);
expect
(
image
.
getAttribute
(
'
title
'
)).
toEqual
(
mockData
.
pipeline
.
user
.
name
);
expect
(
image
.
getAttribute
(
'
src
'
)).
toEqual
(
mockData
.
pipeline
.
user
.
avatar_url
);
});
it
(
'
should render "API" when no user is provided
'
,
()
=>
{
const
component
=
new
PipelineUrlComponent
({
propsData
:
{
pipeline
:
{
id
:
1
,
path
:
'
foo
'
,
flags
:
{},
},
},
}).
$mount
();
expect
(
component
.
$el
.
querySelector
(
'
.js-pipeline-url-api
'
).
textContent
).
toContain
(
'
API
'
);
});
it
(
'
should render latest, yaml invalid and stuck flags when provided
'
,
()
=>
{
const
component
=
new
PipelineUrlComponent
({
propsData
:
{
pipeline
:
{
id
:
1
,
path
:
'
foo
'
,
flags
:
{
latest
:
true
,
yaml_errors
:
true
,
stuck
:
true
,
},
},
},
}).
$mount
();
expect
(
component
.
$el
.
querySelector
(
'
.js-pipeline-url-lastest
'
).
textContent
).
toContain
(
'
latest
'
);
expect
(
component
.
$el
.
querySelector
(
'
.js-pipeline-url-yaml
'
).
textContent
).
toContain
(
'
yaml invalid
'
);
expect
(
component
.
$el
.
querySelector
(
'
.js-pipeline-url-stuck
'
).
textContent
).
toContain
(
'
stuck
'
);
});
});
spec/javascripts/vue_pipelines_index/pipelines_actions_spec.js
0 → 100644
View file @
b0f2cbce
import
Vue
from
'
vue
'
;
import
pipelinesActionsComp
from
'
~/vue_pipelines_index/components/pipelines_actions
'
;
describe
(
'
Pipelines Actions dropdown
'
,
()
=>
{
let
component
;
let
spy
;
let
actions
;
let
ActionsComponent
;
beforeEach
(()
=>
{
ActionsComponent
=
Vue
.
extend
(
pipelinesActionsComp
);
actions
=
[
{
name
:
'
stop_review
'
,
path
:
'
/root/review-app/builds/1893/play
'
,
},
];
spy
=
jasmine
.
createSpy
(
'
spy
'
).
and
.
returnValue
(
Promise
.
resolve
());
component
=
new
ActionsComponent
({
propsData
:
{
actions
,
service
:
{
postAction
:
spy
,
},
},
}).
$mount
();
});
it
(
'
should render a dropdown with the provided actions
'
,
()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
.dropdown-menu li
'
).
length
,
).
toEqual
(
actions
.
length
);
});
it
(
'
should call the service when an action is clicked
'
,
()
=>
{
component
.
$el
.
querySelector
(
'
.js-pipeline-dropdown-manual-actions
'
).
click
();
component
.
$el
.
querySelector
(
'
.js-pipeline-action-link
'
).
click
();
expect
(
spy
).
toHaveBeenCalledWith
(
actions
[
0
].
path
);
});
it
(
'
should hide loading if request fails
'
,
()
=>
{
spy
=
jasmine
.
createSpy
(
'
spy
'
).
and
.
returnValue
(
Promise
.
reject
());
component
=
new
ActionsComponent
({
propsData
:
{
actions
,
service
:
{
postAction
:
spy
,
},
},
}).
$mount
();
component
.
$el
.
querySelector
(
'
.js-pipeline-dropdown-manual-actions
'
).
click
();
component
.
$el
.
querySelector
(
'
.js-pipeline-action-link
'
).
click
();
expect
(
component
.
$el
.
querySelector
(
'
.fa-spinner
'
)).
toEqual
(
null
);
});
});
spec/javascripts/vue_pipelines_index/pipelines_artifacts_spec.js
0 → 100644
View file @
b0f2cbce
import
Vue
from
'
vue
'
;
import
artifactsComp
from
'
~/vue_pipelines_index/components/pipelines_artifacts
'
;
describe
(
'
Pipelines Artifacts dropdown
'
,
()
=>
{
let
component
;
let
artifacts
;
beforeEach
(()
=>
{
const
ArtifactsComponent
=
Vue
.
extend
(
artifactsComp
);
artifacts
=
[
{
name
:
'
artifact
'
,
path
:
'
/download/path
'
,
},
];
component
=
new
ArtifactsComponent
({
propsData
:
{
artifacts
,
},
}).
$mount
();
});
it
(
'
should render a dropdown with the provided artifacts
'
,
()
=>
{
expect
(
component
.
$el
.
querySelectorAll
(
'
.dropdown-menu li
'
).
length
,
).
toEqual
(
artifacts
.
length
);
});
it
(
'
should render a link with the provided path
'
,
()
=>
{
expect
(
component
.
$el
.
querySelector
(
'
.dropdown-menu li a
'
).
getAttribute
(
'
href
'
),
).
toEqual
(
artifacts
[
0
].
path
);
expect
(
component
.
$el
.
querySelector
(
'
.dropdown-menu li a span
'
).
textContent
,
).
toContain
(
artifacts
[
0
].
name
);
});
});
spec/javascripts/vue_pipelines_index/pipelines_store_spec.js
0 → 100644
View file @
b0f2cbce
import
PipelineStore
from
'
~/vue_pipelines_index/stores/pipelines_store
'
;
describe
(
'
Pipelines Store
'
,
()
=>
{
let
store
;
beforeEach
(()
=>
{
store
=
new
PipelineStore
();
});
it
(
'
should be initialized with an empty state
'
,
()
=>
{
expect
(
store
.
state
.
pipelines
).
toEqual
([]);
expect
(
store
.
state
.
count
).
toEqual
({});
expect
(
store
.
state
.
pageInfo
).
toEqual
({});
});
describe
(
'
storePipelines
'
,
()
=>
{
it
(
'
should use the default parameter if none is provided
'
,
()
=>
{
store
.
storePipelines
();
expect
(
store
.
state
.
pipelines
).
toEqual
([]);
});
it
(
'
should store the provided array
'
,
()
=>
{
const
array
=
[{
id
:
1
,
status
:
'
running
'
},
{
id
:
2
,
status
:
'
success
'
}];
store
.
storePipelines
(
array
);
expect
(
store
.
state
.
pipelines
).
toEqual
(
array
);
});
});
describe
(
'
storeCount
'
,
()
=>
{
it
(
'
should use the default parameter if none is provided
'
,
()
=>
{
store
.
storeCount
();
expect
(
store
.
state
.
count
).
toEqual
({});
});
it
(
'
should store the provided count
'
,
()
=>
{
const
count
=
{
all
:
20
,
finished
:
10
};
store
.
storeCount
(
count
);
expect
(
store
.
state
.
count
).
toEqual
(
count
);
});
});
describe
(
'
storePagination
'
,
()
=>
{
it
(
'
should use the default parameter if none is provided
'
,
()
=>
{
store
.
storePagination
();
expect
(
store
.
state
.
pageInfo
).
toEqual
({});
});
it
(
'
should store pagination information normalized and parsed
'
,
()
=>
{
const
pagination
=
{
'
X-nExt-pAge
'
:
'
2
'
,
'
X-page
'
:
'
1
'
,
'
X-Per-Page
'
:
'
1
'
,
'
X-Prev-Page
'
:
'
2
'
,
'
X-TOTAL
'
:
'
37
'
,
'
X-Total-Pages
'
:
'
2
'
,
};
const
expectedResult
=
{
perPage
:
1
,
page
:
1
,
total
:
37
,
totalPages
:
2
,
nextPage
:
2
,
previousPage
:
2
,
};
store
.
storePagination
(
pagination
);
expect
(
store
.
state
.
pageInfo
).
toEqual
(
expectedResult
);
});
});
});
spec/javascripts/vue_shared/components/commit_spec.js
View file @
b0f2cbce
require
(
'
~/vue_shared/components/commit
'
);
import
Vue
from
'
vue
'
;
import
commitComp
from
'
~/vue_shared/components/commit
'
;
describe
(
'
Commit component
'
,
()
=>
{
let
props
;
let
component
;
let
CommitComponent
;
beforeEach
(()
=>
{
CommitComponent
=
Vue
.
extend
(
commitComp
);
});
it
(
'
should render a code-fork icon if it does not represent a tag
'
,
()
=>
{
setFixtures
(
'
<div class="test-commit-container"></div>
'
);
component
=
new
window
.
gl
.
CommitComponent
({
el
:
document
.
querySelector
(
'
.test-commit-container
'
),
component
=
new
CommitComponent
({
propsData
:
{
tag
:
false
,
commitRef
:
{
...
...
@@ -23,15 +27,13 @@ describe('Commit component', () => {
username
:
'
jschatz1
'
,
},
},
});
})
.
$mount
()
;
expect
(
component
.
$el
.
querySelector
(
'
.icon-container i
'
).
classList
).
toContain
(
'
fa-code-fork
'
);
});
describe
(
'
Given all the props
'
,
()
=>
{
beforeEach
(()
=>
{
setFixtures
(
'
<div class="test-commit-container"></div>
'
);
props
=
{
tag
:
true
,
commitRef
:
{
...
...
@@ -49,10 +51,9 @@ describe('Commit component', () => {
commitIconSvg
:
'
<svg></svg>
'
,
};
component
=
new
window
.
gl
.
CommitComponent
({
el
:
document
.
querySelector
(
'
.test-commit-container
'
),
component
=
new
CommitComponent
({
propsData
:
props
,
});
})
.
$mount
()
;
});
it
(
'
should render a tag icon if it represents a tag
'
,
()
=>
{
...
...
@@ -105,7 +106,6 @@ describe('Commit component', () => {
describe
(
'
When commit title is not provided
'
,
()
=>
{
it
(
'
should render default message
'
,
()
=>
{
setFixtures
(
'
<div class="test-commit-container"></div>
'
);
props
=
{
tag
:
false
,
commitRef
:
{
...
...
@@ -118,10 +118,9 @@ describe('Commit component', () => {
author
:
{},
};
component
=
new
window
.
gl
.
CommitComponent
({
el
:
document
.
querySelector
(
'
.test-commit-container
'
),
component
=
new
CommitComponent
({
propsData
:
props
,
});
})
.
$mount
()
;
expect
(
component
.
$el
.
querySelector
(
'
.commit-title span
'
).
textContent
,
...
...
spec/javascripts/vue_shared/components/pipelines_table_row_spec.js
View file @
b0f2cbce
require
(
'
~/vue_shared/components/pipelines_table_row
'
);
const
pipeline
=
require
(
'
../../commit/pipelines/mock_data
'
);
import
Vue
from
'
vue
'
;
import
tableRowComp
from
'
~/vue_shared/components/pipelines_table_row
'
;
import
pipeline
from
'
../../commit/pipelines/mock_data
'
;
describe
(
'
Pipelines Table Row
'
,
()
=>
{
let
component
;
preloadFixtures
(
'
static/environments/element.html.raw
'
);
beforeEach
(()
=>
{
loadFixtures
(
'
static/environments/element.html.raw
'
);
const
PipelinesTableRowComponent
=
Vue
.
extend
(
tableRowComp
);
component
=
new
gl
.
pipelines
.
PipelinesTableRowComponent
({
component
=
new
PipelinesTableRowComponent
({
el
:
document
.
querySelector
(
'
.test-dom-element
'
),
propsData
:
{
pipeline
,
s
vgs
:
{},
s
ervice
:
{},
},
});
})
.
$mount
()
;
});
it
(
'
should render a table row
'
,
()
=>
{
...
...
spec/javascripts/vue_shared/components/pipelines_table_spec.js
View file @
b0f2cbce
require
(
'
~/vue_shared/components/pipelines_table
'
);
require
(
'
~/lib/utils/datetime_utility
'
);
const
pipeline
=
require
(
'
../../commit/pipelines/mock_data
'
);
import
Vue
from
'
vue
'
;
import
pipelinesTableComp
from
'
~/vue_shared/components/pipelines_table
'
;
import
'
~/lib/utils/datetime_utility
'
;
import
pipeline
from
'
../../commit/pipelines/mock_data
'
;
describe
(
'
Pipelines Table
'
,
()
=>
{
preloadFixtures
(
'
static/environments/element.html.raw
'
)
;
let
PipelinesTableComponent
;
beforeEach
(()
=>
{
loadFixtures
(
'
static/environments/element.html.raw
'
);
PipelinesTableComponent
=
Vue
.
extend
(
pipelinesTableComp
);
});
describe
(
'
table
'
,
()
=>
{
let
component
;
beforeEach
(()
=>
{
component
=
new
gl
.
pipelines
.
PipelinesTableComponent
({
el
:
document
.
querySelector
(
'
.test-dom-element
'
),
component
=
new
PipelinesTableComponent
({
propsData
:
{
pipelines
:
[],
s
vgs
:
{},
s
ervice
:
{},
},
});
})
.
$mount
()
;
});
it
(
'
should render a table
'
,
()
=>
{
...
...
@@ -37,26 +37,25 @@ describe('Pipelines Table', () => {
describe
(
'
without data
'
,
()
=>
{
it
(
'
should render an empty table
'
,
()
=>
{
const
component
=
new
gl
.
pipelines
.
PipelinesTableComponent
({
el
:
document
.
querySelector
(
'
.test-dom-element
'
),
const
component
=
new
PipelinesTableComponent
({
propsData
:
{
pipelines
:
[],
s
vgs
:
{},
s
ervice
:
{},
},
});
})
.
$mount
()
;
expect
(
component
.
$el
.
querySelectorAll
(
'
tbody tr
'
).
length
).
toEqual
(
0
);
});
});
describe
(
'
with data
'
,
()
=>
{
it
(
'
should render rows
'
,
()
=>
{
const
component
=
new
gl
.
pipelines
.
PipelinesTableComponent
({
const
component
=
new
PipelinesTableComponent
({
el
:
document
.
querySelector
(
'
.test-dom-element
'
),
propsData
:
{
pipelines
:
[
pipeline
],
s
vgs
:
{},
s
ervice
:
{},
},
});
})
.
$mount
()
;
expect
(
component
.
$el
.
querySelectorAll
(
'
tbody tr
'
).
length
).
toEqual
(
1
);
});
...
...
spec/javascripts/vue_shared/components/table_pagination_spec.js
View file @
b0f2cbce
require
(
'
~/lib/utils/common_utils
'
);
require
(
'
~/vue_shared/components/table_pagination
'
);
import
Vue
from
'
vue
'
;
import
paginationComp
from
'
~/vue_shared/components/table_pagination
'
;
import
'
~/lib/utils/common_utils
'
;
describe
(
'
Pagination component
'
,
()
=>
{
let
component
;
let
PaginationComponent
;
const
changeChanges
=
{
one
:
''
,
...
...
@@ -12,11 +14,12 @@ describe('Pagination component', () => {
changeChanges
.
one
=
one
;
};
it
(
'
should render and start at page 1
'
,
()
=>
{
setFixtures
(
'
<div class="test-pagination-container"></div>
'
);
beforeEach
(()
=>
{
PaginationComponent
=
Vue
.
extend
(
paginationComp
);
});
component
=
new
window
.
gl
.
VueGlPagination
(
{
el
:
document
.
querySelector
(
'
.test-pagination-container
'
),
it
(
'
should render and start at page 1
'
,
()
=>
{
component
=
new
PaginationComponent
({
propsData
:
{
pageInfo
:
{
totalPages
:
10
,
...
...
@@ -25,7 +28,7 @@ describe('Pagination component', () => {
},
change
,
},
});
})
.
$mount
()
;
expect
(
component
.
$el
.
classList
).
toContain
(
'
gl-pagination
'
);
...
...
@@ -35,10 +38,7 @@ describe('Pagination component', () => {
});
it
(
'
should go to the previous page
'
,
()
=>
{
setFixtures
(
'
<div class="test-pagination-container"></div>
'
);
component
=
new
window
.
gl
.
VueGlPagination
({
el
:
document
.
querySelector
(
'
.test-pagination-container
'
),
component
=
new
PaginationComponent
({
propsData
:
{
pageInfo
:
{
totalPages
:
10
,
...
...
@@ -47,7 +47,7 @@ describe('Pagination component', () => {
},
change
,
},
});
})
.
$mount
()
;
component
.
changePage
({
target
:
{
innerText
:
'
Prev
'
}
});
...
...
@@ -55,10 +55,7 @@ describe('Pagination component', () => {
});
it
(
'
should go to the next page
'
,
()
=>
{
setFixtures
(
'
<div class="test-pagination-container"></div>
'
);
component
=
new
window
.
gl
.
VueGlPagination
({
el
:
document
.
querySelector
(
'
.test-pagination-container
'
),
component
=
new
PaginationComponent
({
propsData
:
{
pageInfo
:
{
totalPages
:
10
,
...
...
@@ -67,7 +64,7 @@ describe('Pagination component', () => {
},
change
,
},
});
})
.
$mount
()
;
component
.
changePage
({
target
:
{
innerText
:
'
Next
'
}
});
...
...
@@ -75,10 +72,7 @@ describe('Pagination component', () => {
});
it
(
'
should go to the last page
'
,
()
=>
{
setFixtures
(
'
<div class="test-pagination-container"></div>
'
);
component
=
new
window
.
gl
.
VueGlPagination
({
el
:
document
.
querySelector
(
'
.test-pagination-container
'
),
component
=
new
PaginationComponent
({
propsData
:
{
pageInfo
:
{
totalPages
:
10
,
...
...
@@ -87,7 +81,7 @@ describe('Pagination component', () => {
},
change
,
},
});
})
.
$mount
()
;
component
.
changePage
({
target
:
{
innerText
:
'
Last >>
'
}
});
...
...
@@ -95,10 +89,7 @@ describe('Pagination component', () => {
});
it
(
'
should go to the first page
'
,
()
=>
{
setFixtures
(
'
<div class="test-pagination-container"></div>
'
);
component
=
new
window
.
gl
.
VueGlPagination
({
el
:
document
.
querySelector
(
'
.test-pagination-container
'
),
component
=
new
PaginationComponent
({
propsData
:
{
pageInfo
:
{
totalPages
:
10
,
...
...
@@ -107,7 +98,7 @@ describe('Pagination component', () => {
},
change
,
},
});
})
.
$mount
()
;
component
.
changePage
({
target
:
{
innerText
:
'
<< First
'
}
});
...
...
@@ -115,10 +106,7 @@ describe('Pagination component', () => {
});
it
(
'
should do nothing
'
,
()
=>
{
setFixtures
(
'
<div class="test-pagination-container"></div>
'
);
component
=
new
window
.
gl
.
VueGlPagination
({
el
:
document
.
querySelector
(
'
.test-pagination-container
'
),
component
=
new
PaginationComponent
({
propsData
:
{
pageInfo
:
{
totalPages
:
10
,
...
...
@@ -127,7 +115,7 @@ describe('Pagination component', () => {
},
change
,
},
});
})
.
$mount
()
;
component
.
changePage
({
target
:
{
innerText
:
'
...
'
}
});
...
...
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