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
b3309bb2
Commit
b3309bb2
authored
Feb 03, 2017
by
Filipa Lacerda
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adjustments to receive new data schema
parent
efa05023
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
219 additions
and
576 deletions
+219
-576
app/assets/javascripts/environments/components/environment.js.es6
...ts/javascripts/environments/components/environment.js.es6
+9
-26
app/assets/javascripts/environments/components/environment_item.js.es6
...vascripts/environments/components/environment_item.js.es6
+81
-130
app/assets/javascripts/environments/stores/environments_store.js.es6
...javascripts/environments/stores/environments_store.js.es6
+14
-154
app/assets/stylesheets/pages/environments.scss
app/assets/stylesheets/pages/environments.scss
+9
-7
spec/javascripts/environments/environment_item_spec.js.es6
spec/javascripts/environments/environment_item_spec.js.es6
+59
-78
spec/javascripts/environments/environments_store_spec.js.es6
spec/javascripts/environments/environments_store_spec.js.es6
+4
-44
spec/javascripts/environments/mock_data.js.es6
spec/javascripts/environments/mock_data.js.es6
+43
-137
No files found.
app/assets/javascripts/environments/components/environment.js.es6
View file @
b3309bb2
...
@@ -69,12 +69,10 @@ require('./environment_item');
...
@@ -69,12 +69,10 @@ require('./environment_item');
* Toggles loading property.
* Toggles loading property.
*/
*/
created() {
created() {
gl.environmentsService = new EnvironmentsService(this.endpoint);
const scope = this.$options.getQueryParameter('scope') || this.visibility;
const endpoint = `${this.endpoint}?scope=${scope}`;
const scope = this.$options.getQueryParameter('scope');
gl.environmentsService = new EnvironmentsService(endpoint);
if (scope) {
this.store.storeVisibility(scope);
}
this.isLoading = true;
this.isLoading = true;
...
@@ -82,6 +80,8 @@ require('./environment_item');
...
@@ -82,6 +80,8 @@ require('./environment_item');
.then(resp => resp.json())
.then(resp => resp.json())
.then((json) => {
.then((json) => {
this.store.storeEnvironments(json);
this.store.storeEnvironments(json);
})
.then(() => {
this.isLoading = false;
this.isLoading = false;
})
})
.catch(() => {
.catch(() => {
...
@@ -165,8 +165,7 @@ require('./environment_item');
...
@@ -165,8 +165,7 @@ require('./environment_item');
</a>
</a>
</p>
</p>
<a
<a v-if="canCreateEnvironmentParsed"
v-if="canCreateEnvironmentParsed"
:href="newEnvironmentPath"
:href="newEnvironmentPath"
class="btn btn-create js-new-environment-button">
class="btn btn-create js-new-environment-button">
New Environment
New Environment
...
@@ -174,7 +173,7 @@ require('./environment_item');
...
@@ -174,7 +173,7 @@ require('./environment_item');
</div>
</div>
<div class="table-holder"
<div class="table-holder"
v-if="!isLoading && state.
filteredE
nvironments.length > 0">
v-if="!isLoading && state.
e
nvironments.length > 0">
<table class="table ci-table environments">
<table class="table ci-table environments">
<thead>
<thead>
<tr>
<tr>
...
@@ -187,31 +186,15 @@ require('./environment_item');
...
@@ -187,31 +186,15 @@ require('./environment_item');
</tr>
</tr>
</thead>
</thead>
<tbody>
<tbody>
<template v-for="model in state.
filteredE
nvironments"
<template v-for="model in state.
e
nvironments"
v-bind:model="model">
v-bind:model="model">
<tr is="environment-item"
<tr
is="environment-item"
:model="model"
:model="model"
:toggleRow="toggleRow.bind(model)"
:can-create-deployment="canCreateDeploymentParsed"
:can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"
:can-read-environment="canReadEnvironmentParsed"
:play-icon-svg="playIconSvg"
:play-icon-svg="playIconSvg"
:terminal-icon-svg="terminalIconSvg"
:terminal-icon-svg="terminalIconSvg"
:commit-icon-svg="commitIconSvg"></tr>
:commit-icon-svg="commitIconSvg"></tr>
<tr v-if="model.isOpen && model.children && model.children.length > 0"
is="environment-item"
v-for="children in model.children"
:model="children"
:toggleRow="toggleRow.bind(children)"
:can-create-deployment="canCreateDeploymentParsed"
:can-read-environment="canReadEnvironmentParsed"
:play-icon-svg="playIconSvg"
:terminal-icon-svg="terminalIconSvg"
:commit-icon-svg="commitIconSvg">
</tr>
</template>
</template>
</tbody>
</tbody>
</table>
</table>
...
...
app/assets/javascripts/environments/components/environment_item.js.es6
View file @
b3309bb2
...
@@ -15,12 +15,7 @@ require('./environment_terminal_button');
...
@@ -15,12 +15,7 @@ require('./environment_terminal_button');
/**
/**
* Envrionment Item Component
* Envrionment Item Component
*
*
* Used in a hierarchical structure to show folders with children
* Renders a table row for each environment.
* in a table.
* Recursive component based on [Tree View](https://vuejs.org/examples/tree-view.html)
*
* See this [issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/22539)
* for more information.15
*/
*/
window.gl = window.gl || {};
window.gl = window.gl || {};
...
@@ -45,11 +40,6 @@ require('./environment_terminal_button');
...
@@ -45,11 +40,6 @@ require('./environment_terminal_button');
default: () => ({}),
default: () => ({}),
},
},
toggleRow: {
type: Function,
required: false,
},
canCreateDeployment: {
canCreateDeployment: {
type: Boolean,
type: Boolean,
required: false,
required: false,
...
@@ -76,50 +66,9 @@ require('./environment_terminal_button');
...
@@ -76,50 +66,9 @@ require('./environment_terminal_button');
type: String,
type: String,
required: false,
required: false,
},
},
},
data() {
return {
rowClass: {
'children-row': this.model['vue-isChildren'],
},
};
},
},
computed: {
computed: {
/**
* If an item has a `children` entry it means it is a folder.
* Folder items have different behaviours - it is possible to toggle
* them and show their children.
*
* @returns {Boolean|Undefined}
*/
isFolder() {
return this.model.children && this.model.children.length > 0;
},
/**
* If an item is inside a folder structure will return true.
* Used for css purposes.
*
* @returns {Boolean|undefined}
*/
isChildren() {
return this.model['vue-isChildren'];
},
/**
* Counts the number of environments in each folder.
* Used to show a badge with the counter.
*
* @returns {Number|Undefined} The number of environments for the current folder.
*/
childrenCounter() {
return this.model.children && this.model.children.length;
},
/**
/**
* Verifies if `last_deployment` key exists in the current Envrionment.
* Verifies if `last_deployment` key exists in the current Envrionment.
* This key is required to render most of the html - this method works has
* This key is required to render most of the html - this method works has
...
@@ -128,8 +77,8 @@ require('./environment_terminal_button');
...
@@ -128,8 +77,8 @@ require('./environment_terminal_button');
* @returns {Boolean}
* @returns {Boolean}
*/
*/
hasLastDeploymentKey() {
hasLastDeploymentKey() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
!this.$options.isObjectEmpty(this.model.last_deployment)) {
!this.$options.isObjectEmpty(this.model.la
test.la
st_deployment)) {
return true;
return true;
}
}
return false;
return false;
...
@@ -142,8 +91,9 @@ require('./environment_terminal_button');
...
@@ -142,8 +91,9 @@ require('./environment_terminal_button');
* @returns {Boolean|Undefined}
* @returns {Boolean|Undefined}
*/
*/
hasManualActions() {
hasManualActions() {
return this.model.last_deployment && this.model.last_deployment.manual_actions &&
return this.model.latest.last_deployment &&
this.model.last_deployment.manual_actions.length > 0;
this.model.latest.last_deployment.manual_actions &&
this.model.latest.last_deployment.manual_actions.length > 0;
},
},
/**
/**
...
@@ -163,8 +113,8 @@ require('./environment_terminal_button');
...
@@ -163,8 +113,8 @@ require('./environment_terminal_button');
*/
*/
canRetry() {
canRetry() {
return this.hasLastDeploymentKey &&
return this.hasLastDeploymentKey &&
this.model.last_deployment &&
this.model.la
test.la
st_deployment &&
this.model.last_deployment.deployable;
this.model.la
test.la
st_deployment.deployable;
},
},
/**
/**
...
@@ -173,9 +123,9 @@ require('./environment_terminal_button');
...
@@ -173,9 +123,9 @@ require('./environment_terminal_button');
* @returns {Boolean|Undefined}
* @returns {Boolean|Undefined}
*/
*/
canShowDate() {
canShowDate() {
return this.model.last_deployment &&
return this.model.la
test.la
st_deployment &&
this.model.last_deployment.deployable &&
this.model.la
test.la
st_deployment.deployable &&
this.model.last_deployment.deployable !== undefined;
this.model.la
test.la
st_deployment.deployable !== undefined;
},
},
/**
/**
...
@@ -185,7 +135,7 @@ require('./environment_terminal_button');
...
@@ -185,7 +135,7 @@ require('./environment_terminal_button');
*/
*/
createdDate() {
createdDate() {
return gl.environmentsList.timeagoInstance.format(
return gl.environmentsList.timeagoInstance.format(
this.model.last_deployment.deployable.created_at,
this.model.la
test.la
st_deployment.deployable.created_at,
);
);
},
},
...
@@ -196,7 +146,7 @@ require('./environment_terminal_button');
...
@@ -196,7 +146,7 @@ require('./environment_terminal_button');
*/
*/
manualActions() {
manualActions() {
if (this.hasManualActions) {
if (this.hasManualActions) {
return this.model.last_deployment.manual_actions.map((action) => {
return this.model.la
test.la
st_deployment.manual_actions.map((action) => {
const parsedAction = {
const parsedAction = {
name: gl.text.humanize(action.name),
name: gl.text.humanize(action.name),
play_path: action.play_path,
play_path: action.play_path,
...
@@ -213,10 +163,10 @@ require('./environment_terminal_button');
...
@@ -213,10 +163,10 @@ require('./environment_terminal_button');
* @returns {String}
* @returns {String}
*/
*/
userImageAltDescription() {
userImageAltDescription() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.user &&
this.model.la
test.la
st_deployment.user &&
this.model.last_deployment.user.username) {
this.model.la
test.la
st_deployment.user.username) {
return `${this.model.last_deployment.user.username}'s avatar'`;
return `${this.model.la
test.la
st_deployment.user.username}'s avatar'`;
}
}
return '';
return '';
},
},
...
@@ -227,9 +177,9 @@ require('./environment_terminal_button');
...
@@ -227,9 +177,9 @@ require('./environment_terminal_button');
* @returns {String|Undefined}
* @returns {String|Undefined}
*/
*/
commitTag() {
commitTag() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.tag) {
this.model.la
test.la
st_deployment.tag) {
return this.model.last_deployment.tag;
return this.model.la
test.la
st_deployment.tag;
}
}
return undefined;
return undefined;
},
},
...
@@ -240,8 +190,9 @@ require('./environment_terminal_button');
...
@@ -240,8 +190,9 @@ require('./environment_terminal_button');
* @returns {Object|Undefined}
* @returns {Object|Undefined}
*/
*/
commitRef() {
commitRef() {
if (this.model.last_deployment && this.model.last_deployment.ref) {
if (this.model.latest.last_deployment &&
return this.model.last_deployment.ref;
this.model.latest.last_deployment.ref) {
return this.model.latest.last_deployment.ref;
}
}
return undefined;
return undefined;
},
},
...
@@ -252,10 +203,10 @@ require('./environment_terminal_button');
...
@@ -252,10 +203,10 @@ require('./environment_terminal_button');
* @returns {String|Undefined}
* @returns {String|Undefined}
*/
*/
commitUrl() {
commitUrl() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.commit &&
this.model.la
test.la
st_deployment.commit &&
this.model.last_deployment.commit.commit_path) {
this.model.la
test.la
st_deployment.commit.commit_path) {
return this.model.last_deployment.commit.commit_path;
return this.model.la
test.la
st_deployment.commit.commit_path;
}
}
return undefined;
return undefined;
},
},
...
@@ -266,10 +217,10 @@ require('./environment_terminal_button');
...
@@ -266,10 +217,10 @@ require('./environment_terminal_button');
* @returns {String|Undefined}
* @returns {String|Undefined}
*/
*/
commitShortSha() {
commitShortSha() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.commit &&
this.model.la
test.la
st_deployment.commit &&
this.model.last_deployment.commit.short_id) {
this.model.la
test.la
st_deployment.commit.short_id) {
return this.model.last_deployment.commit.short_id;
return this.model.la
test.la
st_deployment.commit.short_id;
}
}
return undefined;
return undefined;
},
},
...
@@ -280,10 +231,10 @@ require('./environment_terminal_button');
...
@@ -280,10 +231,10 @@ require('./environment_terminal_button');
* @returns {String|Undefined}
* @returns {String|Undefined}
*/
*/
commitTitle() {
commitTitle() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.commit &&
this.model.la
test.la
st_deployment.commit &&
this.model.last_deployment.commit.title) {
this.model.la
test.la
st_deployment.commit.title) {
return this.model.last_deployment.commit.title;
return this.model.la
test.la
st_deployment.commit.title;
}
}
return undefined;
return undefined;
},
},
...
@@ -294,10 +245,10 @@ require('./environment_terminal_button');
...
@@ -294,10 +245,10 @@ require('./environment_terminal_button');
* @returns {Object|Undefined}
* @returns {Object|Undefined}
*/
*/
commitAuthor() {
commitAuthor() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.commit &&
this.model.la
test.la
st_deployment.commit &&
this.model.last_deployment.commit.author) {
this.model.la
test.la
st_deployment.commit.author) {
return this.model.last_deployment.commit.author;
return this.model.la
test.la
st_deployment.commit.author;
}
}
return undefined;
return undefined;
...
@@ -309,10 +260,10 @@ require('./environment_terminal_button');
...
@@ -309,10 +260,10 @@ require('./environment_terminal_button');
* @returns {String|Undefined}
* @returns {String|Undefined}
*/
*/
retryUrl() {
retryUrl() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.deployable &&
this.model.la
test.la
st_deployment.deployable &&
this.model.last_deployment.deployable.retry_path) {
this.model.la
test.la
st_deployment.deployable.retry_path) {
return this.model.last_deployment.deployable.retry_path;
return this.model.la
test.la
st_deployment.deployable.retry_path;
}
}
return undefined;
return undefined;
},
},
...
@@ -323,7 +274,8 @@ require('./environment_terminal_button');
...
@@ -323,7 +274,8 @@ require('./environment_terminal_button');
* @returns {Boolean|Undefined}
* @returns {Boolean|Undefined}
*/
*/
isLastDeployment() {
isLastDeployment() {
return this.model.last_deployment && this.model.last_deployment['last?'];
return this.model.latest.last_deployment &&
this.model.latest.last_deployment['last?'];
},
},
/**
/**
...
@@ -332,9 +284,9 @@ require('./environment_terminal_button');
...
@@ -332,9 +284,9 @@ require('./environment_terminal_button');
* @returns {String}
* @returns {String}
*/
*/
buildName() {
buildName() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.deployable) {
this.model.la
test.la
st_deployment.deployable) {
return `${this.model.la
st_deployment.deployable.name} #${this.model
.last_deployment.deployable.id}`;
return `${this.model.la
test.last_deployment.deployable.name} #${this.model.latest
.last_deployment.deployable.id}`;
}
}
return '';
return '';
},
},
...
@@ -345,9 +297,9 @@ require('./environment_terminal_button');
...
@@ -345,9 +297,9 @@ require('./environment_terminal_button');
* @returns {String}
* @returns {String}
*/
*/
deploymentInternalId() {
deploymentInternalId() {
if (this.model.last_deployment &&
if (this.model.la
test.la
st_deployment &&
this.model.last_deployment.iid) {
this.model.la
test.la
st_deployment.iid) {
return `#${this.model.last_deployment.iid}`;
return `#${this.model.la
test.la
st_deployment.iid}`;
}
}
return '';
return '';
},
},
...
@@ -358,8 +310,8 @@ require('./environment_terminal_button');
...
@@ -358,8 +310,8 @@ require('./environment_terminal_button');
* @returns {Boolean}
* @returns {Boolean}
*/
*/
deploymentHasUser() {
deploymentHasUser() {
return !this.$options.isObjectEmpty(this.model.last_deployment) &&
return !this.$options.isObjectEmpty(this.model.la
test.la
st_deployment) &&
!this.$options.isObjectEmpty(this.model.last_deployment.user);
!this.$options.isObjectEmpty(this.model.la
test.la
st_deployment.user);
},
},
/**
/**
...
@@ -369,9 +321,9 @@ require('./environment_terminal_button');
...
@@ -369,9 +321,9 @@ require('./environment_terminal_button');
* @returns {Object}
* @returns {Object}
*/
*/
deploymentUser() {
deploymentUser() {
if (!this.$options.isObjectEmpty(this.model.last_deployment) &&
if (!this.$options.isObjectEmpty(this.model.la
test.la
st_deployment) &&
!this.$options.isObjectEmpty(this.model.last_deployment.user)) {
!this.$options.isObjectEmpty(this.model.la
test.la
st_deployment.user)) {
return this.model.last_deployment.user;
return this.model.la
test.la
st_deployment.user;
}
}
return {};
return {};
},
},
...
@@ -384,9 +336,9 @@ require('./environment_terminal_button');
...
@@ -384,9 +336,9 @@ require('./environment_terminal_button');
* @returns {Boolean}
* @returns {Boolean}
*/
*/
shouldRenderBuildName() {
shouldRenderBuildName() {
return !this.isFolder &&
return !this.
model.
isFolder &&
!this.$options.isObjectEmpty(this.model.last_deployment) &&
!this.$options.isObjectEmpty(this.model.la
test.la
st_deployment) &&
!this.$options.isObjectEmpty(this.model.last_deployment.deployable);
!this.$options.isObjectEmpty(this.model.la
test.la
st_deployment.deployable);
},
},
/**
/**
...
@@ -397,9 +349,9 @@ require('./environment_terminal_button');
...
@@ -397,9 +349,9 @@ require('./environment_terminal_button');
* @returns {Boolean}
* @returns {Boolean}
*/
*/
shouldRenderDeploymentID() {
shouldRenderDeploymentID() {
return !this.isFolder &&
return !this.
model.
isFolder &&
!this.$options.isObjectEmpty(this.model.last_deployment) &&
!this.$options.isObjectEmpty(this.model.la
test.la
st_deployment) &&
this.model.last_deployment.iid !== undefined;
this.model.la
test.la
st_deployment.iid !== undefined;
},
},
},
},
...
@@ -420,16 +372,16 @@ require('./environment_terminal_button');
...
@@ -420,16 +372,16 @@ require('./environment_terminal_button');
template: `
template: `
<tr>
<tr>
<td
v-bind:class="{ 'children-row': isChildren}"
>
<td>
<a v-if="!isFolder"
<a v-if="!
model.
isFolder"
class="environment-name"
class="environment-name"
:href="model.environment_path">
:href="model.
latest.
environment_path">
{{model.name}}
{{model.name}}
</a>
</a>
<
span v-else v-on:click="toggleRow(model)"
class="folder-name">
<
a v-else
class="folder-name">
<span class="folder-icon">
<span class="folder-icon">
<i
v-show="model.isOpen" class="fa fa-caret-down
"></i>
<i
class="fa fa-caret-right" aria-hidden="true
"></i>
<i
v-show="!model.isOpen" class="fa fa-caret-right
"></i>
<i
class="fa fa-folder" aria-hidden="true
"></i>
</span>
</span>
<span>
<span>
...
@@ -437,9 +389,9 @@ require('./environment_terminal_button');
...
@@ -437,9 +389,9 @@ require('./environment_terminal_button');
</span>
</span>
<span class="badge">
<span class="badge">
{{
childrenCounter
}}
{{
model.size
}}
</span>
</span>
</
span
>
</
a
>
</td>
</td>
<td class="deployment-column">
<td class="deployment-column">
...
@@ -447,7 +399,7 @@ require('./environment_terminal_button');
...
@@ -447,7 +399,7 @@ require('./environment_terminal_button');
{{deploymentInternalId}}
{{deploymentInternalId}}
</span>
</span>
<span v-if="!isFolder && deploymentHasUser">
<span v-if="!
model.
isFolder && deploymentHasUser">
by
by
<a :href="deploymentUser.web_url" class="js-deploy-user-container">
<a :href="deploymentUser.web_url" class="js-deploy-user-container">
<img class="avatar has-tooltip s20"
<img class="avatar has-tooltip s20"
...
@@ -461,13 +413,13 @@ require('./environment_terminal_button');
...
@@ -461,13 +413,13 @@ require('./environment_terminal_button');
<td class="environments-build-cell">
<td class="environments-build-cell">
<a v-if="shouldRenderBuildName"
<a v-if="shouldRenderBuildName"
class="build-link"
class="build-link"
:href="model.last_deployment.deployable.build_path">
:href="model.la
test.la
st_deployment.deployable.build_path">
{{buildName}}
{{buildName}}
</a>
</a>
</td>
</td>
<td>
<td>
<div v-if="!isFolder && hasLastDeploymentKey" class="js-commit-component">
<div v-if="!
model.
isFolder && hasLastDeploymentKey" class="js-commit-component">
<commit-component
<commit-component
:tag="commitTag"
:tag="commitTag"
:commit-ref="commitRef"
:commit-ref="commitRef"
...
@@ -478,21 +430,20 @@ require('./environment_terminal_button');
...
@@ -478,21 +430,20 @@ require('./environment_terminal_button');
:commit-icon-svg="commitIconSvg">
:commit-icon-svg="commitIconSvg">
</commit-component>
</commit-component>
</div>
</div>
<p v-if="!isFolder && !hasLastDeploymentKey" class="commit-title">
<p v-if="!
model.
isFolder && !hasLastDeploymentKey" class="commit-title">
No deployments yet
No deployments yet
</p>
</p>
</td>
</td>
<td>
<td>
<span
<span v-if="!model.isFolder && canShowDate"
v-if="!isFolder && canShowDate"
class="environment-created-date-timeago">
class="environment-created-date-timeago">
{{createdDate}}
{{createdDate}}
</span>
</span>
</td>
</td>
<td class="hidden-xs">
<td class="hidden-xs">
<div v-if="!isFolder">
<div v-if="!
model.
isFolder">
<div v-if="hasManualActions && canCreateDeployment"
<div v-if="hasManualActions && canCreateDeployment"
class="inline js-manual-actions-container">
class="inline js-manual-actions-container">
<actions-component
<actions-component
...
@@ -501,25 +452,25 @@ require('./environment_terminal_button');
...
@@ -501,25 +452,25 @@ require('./environment_terminal_button');
</actions-component>
</actions-component>
</div>
</div>
<div v-if="model.external_url && canReadEnvironment"
<div v-if="model.
latest.
external_url && canReadEnvironment"
class="inline js-external-url-container">
class="inline js-external-url-container">
<external-url-component
<external-url-component
:external-url="model.external_url">
:external-url="model.
latest.
external_url">
</external-url-component>
</external-url-component>
</div>
</div>
<div v-if="hasStopAction && canCreateDeployment"
<div v-if="hasStopAction && canCreateDeployment"
class="inline js-stop-component-container">
class="inline js-stop-component-container">
<stop-component
<stop-component
:stop-url="model.stop_path">
:stop-url="model.
latest.
stop_path">
</stop-component>
</stop-component>
</div>
</div>
<div v-if="model.terminal_path"
<div v-if="model.
latest.
terminal_path"
class="inline js-terminal-button-container">
class="inline js-terminal-button-container">
<terminal-button-component
<terminal-button-component
:terminal-icon-svg="terminalIconSvg"
:terminal-icon-svg="terminalIconSvg"
:terminal-path="model.terminal_path">
:terminal-path="model.
latest.
terminal_path">
</terminal-button-component>
</terminal-button-component>
</div>
</div>
...
...
app/assets/javascripts/environments/stores/environments_store.js.es6
View file @
b3309bb2
...
@@ -10,181 +10,41 @@
...
@@ -10,181 +10,41 @@
this.state.environments = [];
this.state.environments = [];
this.state.stoppedCounter = 0;
this.state.stoppedCounter = 0;
this.state.availableCounter = 0;
this.state.availableCounter = 0;
this.state.visibility = 'available';
this.state.filteredEnvironments = [];
this.state.filteredEnvironments = [];
return this;
return this;
},
},
/**
/**
* In order to display a tree view we need to modify the received
* data in to a tree structure based on `environment_type`
* sorted alphabetically.
* In each children a `vue-` property will be added. This property will be
* used to know if an item is a children mostly for css purposes. This is
* needed because the children row is a fragment instance and therfore does
* not accept non-prop attributes.
*
*
* Stores the received environments.
*
*
* @example
* Each environment has the following schema
* it will transform this:
* { name: String, size: Number, latest: Object }
* [
* { name: "environment", environment_type: "review" },
* { name: "environment_1", environment_type: null }
* { name: "environment_2, environment_type: "review" }
* ]
* into this:
* [
* { name: "review", children:
* [
* { name: "environment", environment_type: "review", vue-isChildren: true},
* { name: "environment_2", environment_type: "review", vue-isChildren: true}
* ]
* },
* {name: "environment_1", environment_type: null}
* ]
*
*
* If the `size` is bigger than 1, it means it should be rendered as a folder.
* In those cases we add `isFolder` key in order to render it properly.
*
*
* @param {Array} environments
List of environments.
* @param {Array} environments
* @returns {Array}
Tree structured array with the received environments.
* @returns {Array}
*/
*/
storeEnvironments(environments = []) {
storeEnvironments(environments = []) {
this.state.stoppedCounter = this.countByState(environments, 'stopped');
const filteredEnvironments = environments.map((env) => {
this.state.availableCounter = this.countByState(environments, 'available');
if (env.size > 1) {
return Object.assign({}, env, { isFolder: true });
const environmentsTree = environments.reduce((acc, environment) => {
if (environment.environment_type !== null) {
const occurs = acc.filter(element => element.children &&
element.name === environment.environment_type);
environment['vue-isChildren'] = true;
if (occurs.length) {
acc[acc.indexOf(occurs[0])].children.push(environment);
acc[acc.indexOf(occurs[0])].children.slice().sort(this.sortByName);
} else {
acc.push({
name: environment.environment_type,
children: [environment],
isOpen: false,
'vue-isChildren': environment['vue-isChildren'],
});
}
} else {
acc.push(environment);
}
return acc;
}, []).slice().sort(this.sortByName);
this.state.environments = environmentsTree;
this.filterEnvironmentsByVisibility(this.state.environments);
return environmentsTree;
},
storeVisibility(visibility) {
this.state.visibility = visibility;
},
/**
* Given the visibility prop provided by the url query parameter and which
* changes according to the active tab we need to filter which environments
* should be visible.
*
* The environments array is a recursive tree structure and we need to filter
* both root level environments and children environments.
*
* In order to acomplish that, both `filterState` and `filterEnvironmentsByVisibility`
* functions work together.
* The first one works as the filter that verifies if the given environment matches
* the given state.
* The second guarantees both root level and children elements are filtered as well.
*
* Given array of environments will return only
* the environments that match the state stored.
*
* @param {Array} array
* @return {Array}
*/
filterEnvironmentsByVisibility(arr) {
const filteredEnvironments = arr.map((item) => {
if (item.children) {
const filteredChildren = this.filterEnvironmentsByVisibility(
item.children,
).filter(Boolean);
if (filteredChildren.length) {
item.children = filteredChildren;
return item;
}
}
return this.filterState(this.state.visibility, item);
}).filter(Boolean);
this.state.filteredEnvironments = filteredEnvironments;
return filteredEnvironments;
},
/**
* Given the state and the environment,
* returns only if the environment state matches the one provided.
*
* @param {String} state
* @param {Object} environment
* @return {Object}
*/
filterState(state, environment) {
return environment.state === state && environment;
},
/**
* Toggles folder open property given the environment type.
*
* @param {String} envType
* @return {Array}
*/
toggleFolder(envType) {
const environments = this.state.environments;
const environmentsCopy = environments.map((env) => {
if (env['vue-isChildren'] && env.name === envType) {
env.isOpen = !env.isOpen;
}
}
return env;
return env;
});
});
this.state.environments =
environmentsCopy
;
this.state.environments =
filteredEnvironments
;
return
environmentsCopy
;
return
filteredEnvironments
;
},
},
/**
storeCounts() {
* Given an array of environments, returns the number of environments
//TODO
* that have the given state.
*
* @param {Array} environments
* @param {String} state
* @returns {Number}
*/
countByState(environments, state) {
return environments.filter(env => env.state === state).length;
},
},
/**
* Sorts the two objects provided by their name.
*
* @param {Object} a
* @param {Object} b
* @returns {Number}
*/
sortByName(a, b) {
const nameA = a.name.toUpperCase();
const nameB = b.name.toUpperCase();
return nameA < nameB ? -1 : nameA > nameB ? 1 : 0; // eslint-disable-line
},
};
};
})();
})();
app/assets/stylesheets/pages/environments.scss
View file @
b3309bb2
...
@@ -110,17 +110,19 @@
...
@@ -110,17 +110,19 @@
}
}
}
}
.children-row
.environment-name
{
margin-left
:
17px
;
margin-right
:
-17px
;
}
.folder-icon
{
.folder-icon
{
padding
:
0
5px
0
0
;
margin-right
:
3px
;
color
:
$gl-text-color-secondary
;
.fa
:nth-child
(
1
)
{
margin-right
:
3px
;
}
}
}
.folder-name
{
.folder-name
{
cursor
:
pointer
;
cursor
:
pointer
;
text-decoration
:
none
;
color
:
$gl-text-color-secondary
;
}
}
}
}
...
@@ -135,4 +137,4 @@
...
@@ -135,4 +137,4 @@
margin-right
:
0
;
margin-right
:
0
;
}
}
}
}
}
}
\ No newline at end of file
spec/javascripts/environments/environment_item_spec.js.es6
View file @
b3309bb2
...
@@ -14,33 +14,13 @@ describe('Environment item', () => {
...
@@ -14,33 +14,13 @@ describe('Environment item', () => {
beforeEach(() => {
beforeEach(() => {
mockItem = {
mockItem = {
name: 'review',
name: 'review',
children: [
size: 3
{
name: 'review-app',
id: 1,
state: 'available',
external_url: '',
last_deployment: {},
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-10T15:55:58.778Z',
},
{
name: 'production',
id: 2,
state: 'available',
external_url: '',
last_deployment: {},
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-10T15:55:58.778Z',
},
],
};
};
component = new window.gl.environmentsList.EnvironmentItem({
component = new window.gl.environmentsList.EnvironmentItem({
el: document.querySelector('tr#environment-row'),
el: document.querySelector('tr#environment-row'),
propsData: {
propsData: {
model: mockItem,
model: mockItem,
toggleRow: () => {},
canCreateDeployment: false,
canCreateDeployment: false,
canReadEnvironment: true,
canReadEnvironment: true,
},
},
...
@@ -53,7 +33,7 @@ describe('Environment item', () => {
...
@@ -53,7 +33,7 @@ describe('Environment item', () => {
});
});
it('Should render the number of children in a badge', () => {
it('Should render the number of children in a badge', () => {
expect(component.$el.querySelector('.folder-name .badge').textContent).toContain(mockItem.
children.length
);
expect(component.$el.querySelector('.folder-name .badge').textContent).toContain(mockItem.
size
);
});
});
});
});
...
@@ -63,38 +43,23 @@ describe('Environment item', () => {
...
@@ -63,38 +43,23 @@ describe('Environment item', () => {
beforeEach(() => {
beforeEach(() => {
environment = {
environment = {
id: 31,
name: 'production',
name: 'production',
state: 'stopped',
size: 1,
external_url: 'http://external.com',
latest: {
environment_type: null,
state: 'stopped',
last_deployment: {
external_url: 'http://external.com',
id: 66,
environment_type: null,
iid: 6,
last_deployment: {
sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
id: 66,
ref: {
iid: 6,
name: 'master',
sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
ref_path: 'root/ci-folders/tree/master',
ref: {
},
name: 'master',
tag: true,
ref_path: 'root/ci-folders/tree/master',
'last?': true,
},
user: {
tag: true,
name: 'Administrator',
'last?': true,
username: 'root',
user: {
id: 1,
state: 'active',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
commit: {
id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
short_id: '500aabcb',
title: 'Update .gitlab-ci.yml',
author_name: 'Administrator',
author_email: 'admin@example.com',
created_at: '2016-11-07T18:28:13.000+00:00',
message: 'Update .gitlab-ci.yml',
author: {
name: 'Administrator',
name: 'Administrator',
username: 'root',
username: 'root',
id: 1,
id: 1,
...
@@ -102,34 +67,50 @@ describe('Environment item', () => {
...
@@ -102,34 +67,50 @@ describe('Environment item', () => {
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
web_url: 'http://localhost:3000/root',
},
},
commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
commit: {
},
id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
deployable: {
short_id: '500aabcb',
id: 1279,
title: 'Update .gitlab-ci.yml',
name: 'deploy',
author_name: 'Administrator',
build_path: '/root/ci-folders/builds/1279',
author_email: 'admin@example.com',
retry_path: '/root/ci-folders/builds/1279/retry',
created_at: '2016-11-07T18:28:13.000+00:00',
created_at: '2016-11-29T18:11:58.430Z',
message: 'Update .gitlab-ci.yml',
updated_at: '2016-11-29T18:11:58.430Z',
author: {
},
name: 'Administrator',
manual_actions: [
username: 'root',
{
id: 1,
name: 'action',
state: 'active',
play_path: '/play',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
},
},
],
deployable: {
id: 1279,
name: 'deploy',
build_path: '/root/ci-folders/builds/1279',
retry_path: '/root/ci-folders/builds/1279/retry',
created_at: '2016-11-29T18:11:58.430Z',
updated_at: '2016-11-29T18:11:58.430Z',
},
manual_actions: [
{
name: 'action',
play_path: '/play',
},
],
},
'stop_action?': true,
environment_path: 'root/ci-folders/environments/31',
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-10T15:55:58.778Z',
},
},
'stop_action?': true,
environment_path: 'root/ci-folders/environments/31',
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-10T15:55:58.778Z',
};
};
component = new window.gl.environmentsList.EnvironmentItem({
component = new window.gl.environmentsList.EnvironmentItem({
el: document.querySelector('tr#environment-row'),
el: document.querySelector('tr#environment-row'),
propsData: {
propsData: {
model: environment,
model: environment,
toggleRow: () => {},
canCreateDeployment: true,
canCreateDeployment: true,
canReadEnvironment: true,
canReadEnvironment: true,
},
},
...
@@ -144,7 +125,7 @@ describe('Environment item', () => {
...
@@ -144,7 +125,7 @@ describe('Environment item', () => {
it('should render deployment internal id', () => {
it('should render deployment internal id', () => {
expect(
expect(
component.$el.querySelector('.deployment-column span').textContent,
component.$el.querySelector('.deployment-column span').textContent,
).toContain(environment.last_deployment.iid);
).toContain(environment.la
test.la
st_deployment.iid);
expect(
expect(
component.$el.querySelector('.deployment-column span').textContent,
component.$el.querySelector('.deployment-column span').textContent,
...
@@ -154,7 +135,7 @@ describe('Environment item', () => {
...
@@ -154,7 +135,7 @@ describe('Environment item', () => {
it('should render last deployment date', () => {
it('should render last deployment date', () => {
const timeagoInstance = new timeago(); // eslint-disable-line
const timeagoInstance = new timeago(); // eslint-disable-line
const formatedDate = timeagoInstance.format(
const formatedDate = timeagoInstance.format(
environment.last_deployment.deployable.created_at,
environment.la
test.la
st_deployment.deployable.created_at,
);
);
expect(
expect(
...
@@ -166,7 +147,7 @@ describe('Environment item', () => {
...
@@ -166,7 +147,7 @@ describe('Environment item', () => {
it('should render user avatar with link to profile', () => {
it('should render user avatar with link to profile', () => {
expect(
expect(
component.$el.querySelector('.js-deploy-user-container').getAttribute('href'),
component.$el.querySelector('.js-deploy-user-container').getAttribute('href'),
).toEqual(environment.last_deployment.user.web_url);
).toEqual(environment.la
test.la
st_deployment.user.web_url);
});
});
});
});
...
@@ -174,13 +155,13 @@ describe('Environment item', () => {
...
@@ -174,13 +155,13 @@ describe('Environment item', () => {
it('Should link to build url provided', () => {
it('Should link to build url provided', () => {
expect(
expect(
component.$el.querySelector('.build-link').getAttribute('href'),
component.$el.querySelector('.build-link').getAttribute('href'),
).toEqual(environment.last_deployment.deployable.build_path);
).toEqual(environment.la
test.la
st_deployment.deployable.build_path);
});
});
it('Should render deployable name and id', () => {
it('Should render deployable name and id', () => {
expect(
expect(
component.$el.querySelector('.build-link').getAttribute('href'),
component.$el.querySelector('.build-link').getAttribute('href'),
).toEqual(environment.last_deployment.deployable.build_path);
).toEqual(environment.la
test.la
st_deployment.deployable.build_path);
});
});
});
});
...
...
spec/javascripts/environments/environments_store_spec.js.es6
View file @
b3309bb2
...
@@ -20,50 +20,10 @@ require('./mock_data');
...
@@ -20,50 +20,10 @@ require('./mock_data');
gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList);
gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList);
});
});
it('should count stopped environments and save the count in the state', () => {
it('should store environments', () => {
expect(gl.environmentsList.EnvironmentsStore.state.stoppedCounter).toBe(1);
expect(
});
gl.environmentsList.EnvironmentsStore.state.environments.length
).toBe(environmentsList.length);
it('should count available environments and save the count in the state', () => {
expect(gl.environmentsList.EnvironmentsStore.state.availableCounter).toBe(3);
});
it('should store environments with same environment_type as sibilings', () => {
expect(gl.environmentsList.EnvironmentsStore.state.environments.length).toBe(3);
const parentFolder = gl.environmentsList.EnvironmentsStore.state.environments
.filter(env => env.children && env.children.length > 0);
expect(parentFolder[0].children.length).toBe(2);
expect(parentFolder[0].children[0].environment_type).toBe('review');
expect(parentFolder[0].children[1].environment_type).toBe('review');
expect(parentFolder[0].children[0].name).toBe('test-environment');
expect(parentFolder[0].children[1].name).toBe('test-environment-1');
});
it('should sort the environments alphabetically', () => {
const { environments } = gl.environmentsList.EnvironmentsStore.state;
expect(environments[0].name).toBe('production');
expect(environments[1].name).toBe('review');
expect(environments[1].children[0].name).toBe('test-environment');
expect(environments[1].children[1].name).toBe('test-environment-1');
expect(environments[2].name).toBe('review_app');
});
});
describe('toggleFolder', () => {
beforeEach(() => {
gl.environmentsList.EnvironmentsStore.storeEnvironments(environmentsList);
});
it('should toggle the open property for the given environment', () => {
gl.environmentsList.EnvironmentsStore.toggleFolder('review');
const { environments } = gl.environmentsList.EnvironmentsStore.state;
const environment = environments.filter(env => env['vue-isChildren'] === true && env.name === 'review');
expect(environment[0].isOpen).toBe(true);
});
});
});
});
});
});
...
...
spec/javascripts/environments/mock_data.js.es6
View file @
b3309bb2
const environmentsList = [
const environmentsList = [
{
{
id: 31,
name: 'DEV',
name: 'production',
size: 1,
state: 'available',
latest: {
external_url: 'https://www.gitlab.com',
id: 7,
environment_type: null,
name: 'DEV',
last_deployment: {
state: 'available',
id: 64,
external_url: null,
iid: 5,
environment_type: null,
sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
last_deployment: null,
ref: {
'stop_action?': false,
name: 'master',
environment_path: '/root/review-app/environments/7',
ref_url: 'http://localhost:3000/root/ci-folders/tree/master',
stop_path: '/root/review-app/environments/7/stop',
},
created_at: '2017-01-31T10:53:46.894Z',
tag: false,
updated_at: '2017-01-31T10:53:46.894Z',
'last?': true,
user: {
name: 'Administrator',
username: 'root',
id: 1,
state: 'active',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
commit: {
id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
short_id: '500aabcb',
title: 'Update .gitlab-ci.yml',
author_name: 'Administrator',
author_email: 'admin@example.com',
created_at: '2016-11-07T18:28:13.000+00:00',
message: 'Update .gitlab-ci.yml',
author: {
name: 'Administrator',
username: 'root',
id: 1,
state: 'active',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
},
deployable: {
id: 1278,
name: 'build',
build_path: '/root/ci-folders/builds/1278',
retry_path: '/root/ci-folders/builds/1278/retry',
},
manual_actions: [],
},
},
'stop_action?': true,
environment_path: '/root/ci-folders/environments/31',
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-07T11:11:16.525Z',
},
},
{
{
id: 32,
name: 'build',
name: 'review_app',
size: 5,
state: 'stopped',
latest: {
external_url: 'https://www.gitlab.com',
id: 12,
environment_type: null,
name: 'build/update-README',
last_deployment: {
state: 'available',
id: 64,
external_url: null,
iid: 5,
environment_type: 'build',
sha: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
last_deployment: null,
ref: {
'stop_action?': false,
name: 'master',
environment_path: '/root/review-app/environments/12',
ref_url: 'http://localhost:3000/root/ci-folders/tree/master',
stop_path: '/root/review-app/environments/12/stop',
},
created_at: '2017-02-01T19:42:18.400Z',
tag: false,
updated_at: '2017-02-01T19:42:18.400Z',
'last?': true,
user: {
name: 'Administrator',
username: 'root',
id: 1,
state: 'active',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
commit: {
id: '500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
short_id: '500aabcb',
title: 'Update .gitlab-ci.yml',
author_name: 'Administrator',
author_email: 'admin@example.com',
created_at: '2016-11-07T18:28:13.000+00:00',
message: 'Update .gitlab-ci.yml',
author: {
name: 'Administrator',
username: 'root',
id: 1,
state: 'active',
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80\u0026d=identicon',
web_url: 'http://localhost:3000/root',
},
commit_path: '/root/ci-folders/tree/500aabcb17c97bdcf2d0c410b70cb8556f0362dd',
},
deployable: {
id: 1278,
name: 'build',
build_path: '/root/ci-folders/builds/1278',
retry_path: '/root/ci-folders/builds/1278/retry',
},
manual_actions: [],
},
},
'stop_action?': false,
environment_path: '/root/ci-folders/environments/31',
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-07T11:11:16.525Z',
},
{
id: 33,
name: 'test-environment',
state: 'available',
environment_type: 'review',
last_deployment: null,
'stop_action?': true,
environment_path: '/root/ci-folders/environments/31',
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-07T11:11:16.525Z',
},
{
id: 34,
name: 'test-environment-1',
state: 'available',
environment_type: 'review',
last_deployment: null,
'stop_action?': true,
environment_path: '/root/ci-folders/environments/31',
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-07T11:11:16.525Z',
},
},
];
];
window.environmentsList = environmentsList;
window.environmentsList = environmentsList;
const environment = {
const environment = {
id: 4,
name: 'DEV',
name: 'production',
size: 1,
state: 'available',
latest: {
external_url: 'http://production.',
id: 7,
environment_type: null,
name: 'DEV',
last_deployment: {},
state: 'available',
'stop_action?': false,
external_url: null,
environment_path: '/root/review-app/environments/4',
environment_type: null,
stop_path: '/root/review-app/environments/4/stop',
last_deployment: null,
created_at: '2016-12-16T11:51:04.690Z',
'stop_action?': false,
updated_at: '2016-12-16T12:04:51.133Z',
environment_path: '/root/review-app/environments/7',
stop_path: '/root/review-app/environments/7/stop',
created_at: '2017-01-31T10:53:46.894Z',
updated_at: '2017-01-31T10:53:46.894Z',
},
};
};
window.environment = environment;
window.environment = environment;
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