diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2017-05-17 17:07:56 +0100 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2017-05-17 17:07:56 +0100 |
commit | 030a86a716327d362b0490ce5ba273e3aea8f398 (patch) | |
tree | 0008c82fa64bffa42159c58963d89d677106e708 | |
parent | 743333486b8b0772cc5555c229c7792ed33dcc50 (diff) | |
download | gitlab-ce-24339-job-page-sidebar-step-3.tar.gz |
Split up sidebar into smaller components24339-job-page-sidebar-step-3
11 files changed, 382 insertions, 230 deletions
diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js index 97f279e4be4..cb19e23db93 100644 --- a/app/assets/javascripts/build.js +++ b/app/assets/javascripts/build.js @@ -72,8 +72,8 @@ window.Build = (function () { } Build.prototype.initSidebar = function () { - this.$sidebar = $('.js-build-sidebar'); - this.$sidebar.niceScroll(); + // this.$sidebar = $('.js-build-sidebar'); + // this.$sidebar.niceScroll(); this.$document .off('click', '.js-sidebar-build-toggle') .on('click', '.js-sidebar-build-toggle', this.toggleSidebar); @@ -263,8 +263,8 @@ window.Build = (function () { .toggleClass('sidebar-collapsed', shouldHide); this.$truncatedInfo.toggleClass('sidebar-expanded', shouldShow) .toggleClass('sidebar-collapsed', shouldHide); - this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow) - .toggleClass('right-sidebar-collapsed', shouldHide); + // this.$sidebar.toggleClass('right-sidebar-expanded', shouldShow) + // .toggleClass('right-sidebar-collapsed', shouldHide); }; Build.prototype.sidebarOnResize = function () { diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue index 731a43e5dae..20e230f8c11 100644 --- a/app/assets/javascripts/jobs/components/sidebar.vue +++ b/app/assets/javascripts/jobs/components/sidebar.vue @@ -1,9 +1,10 @@ <script> -import artifactsLink from './artifacts_link.vue'; -import ciIcon from '../../vue_shared/components/ci_icon.vue'; -import copyClipboard from '../../vue_shared/components/copy_to_clipboard.vue'; -import detailRow from './sidebar_detail_row.vue'; -import tooltipMixin from '../../vue_shared/mixins/tooltip'; +import sidebarArtifacts from './sidebar_artifacts_block.vue'; +import sidebarCommit from './sidebar_commit_block.vue'; +import sidebarInformation from './sidebar_information_block.vue'; +import sidebarRelatedJobs from './sidebar_related_jobs_block.vue'; +import sidebarStages from './sidebar_stages_block.vue'; +import sidebarTags from './sidebar_tags_block.vue'; /** * Sidebar component for job's detail page based on UX Mockups @@ -15,10 +16,6 @@ import tooltipMixin from '../../vue_shared/mixins/tooltip'; export default { name: 'SidebarJob', - mixins: [ - tooltipMixin, - ], - props: { job: { type: Object, @@ -27,255 +24,89 @@ export default { }, components: { - artifactsLink, - ciIcon, - copyClipboard, - detailRow, + sidebarArtifacts, + sidebarCommit, + sidebarInformation, + sidebarRelatedJobs, + sidebarStages, + sidebarTags, }, computed: { - artifactsExpired() { - return `The artifacts were removed ${this.timeFormated(this.job.artifactsExpiredAt)}`; - }, - coverage() { - return `${this.job.coverage}%`; - }, - duration() { - return this.job.details.duration; + hasRelatedJobs() { + return this.job.relatedJobs && this.job.relatedJobs.length > 1; }, - expiringArtifacts() { - return `The artifacts will be removed in ${this.job.artifactsExpireAt}`; - }, - hasArtifacts() { - return this.job.artifacts.lenght; + + hasStages() { + return this.job.details && this.job.details.stages && this.job.details.stages.length > 1; }, - queued() { - return this.job.details.queued; + + hasTags() { + return this.job.tags && this.job.tags.length; }, }, - created() { - // TODO move sidebar implementation to vue - new Sidebar(); + + mounted() { + $(this.$el).affix({ + offset: { + top: 101, + }, + }); }, methods: { - timeFormated(time) { - const timeago = gl.utils.getTimeago(); - - return timeago.format(time); - }, - relatedJobClassName(job) { - let className = ''; - if (job.active) { - className = 'active'; - } - - if (job.retried) { - className = 'retried'; - } - return className; + toggleSidebar() { + this.$el.classList + .toggle('right-sidebar-expanded') + .toggle('right-sidebar-collapsed'); }, }, }; </script> <template> - <aside - class="js-build-sidebar js-right-sidebar right-sidebar build-sidebar affix-top right-sidebar-expanded" - data-offset-top="101" - data-spy="affix"> + <aside class="js-build-sidebar right-sidebar build-sidebar affix-top right-sidebar-expanded"> - <div - class="block build-sidebar-header visible-xs-block visible-sm-block append-bottom-default"> - <a - class="js-sidebar-build-toggle gutter-toggle pull-right" - href="#"> + <div class="block build-sidebar-header visible-xs-block visible-sm-block append-bottom-default"> + <button + @click="toggleSidebar" + class="gutter-toggle pull-right"> <i class="fa fa-angle-double-right" aria-hidden="true" title="Toggle Sidebar" aria-labelledby="job-title"> </i> - </a> + </button> </div> <div class="blocks-container"> - <!-- name --> <div class="block"> <strong>{{job.name}}</strong> </div> - <!-- information --> - <div class="block"> - <detail-row - v-if="duration" - title="Duration:" - :value="timeFormated(duration)" - /> - <detail-row - v-if="job.finishedAt" - title="Finished:" - :value="timeFormated(job.finishedAt)" - /> - <detail-row - v-if="job.erasedAt" - title="Erased:" - :value="timeFormated(job.erasedAt)" - /> - <detail-row - v-if="queued" - title="Queued:" - :value="timeFormated(queued)" - /> - <detail-row - v-if="job.details.runner" - title="Runner:" - :value="job.details.runner.id" - /> - <detail-row - v-if="job.coverage" - title="Coverage:" - :value="coverage" - /> - </div> + <sidebar-information :job="job" /> - <!-- artifacts --> - <div class="block"> - <detail-row - v-if="job.flags.artifacts_expired" - :value="artifactsExpired" - /> - <detail-row - v-if="job.flags.has_expiring_artifacts" - :value="expiringArtifacts" - /> - <artifacts-link - v-if="job.flags.has_expiring_artifacts && job.permission.canUpdateBuild" - label="Keep" - :link="job.paths.keep" - /> - <artifacts-link - label="Download" - :link="job.paths.download" - /> - <artifacts-link - v-if="job.flags.artifacts_metadata" - label="Browse" - :link="job.paths.browse" - /> - </div> - - <!-- commit --> - <div class="block" v-if="job.commit"> - <div class="title"> - Commit - <a - :href="job.commit.commit_url" - class="commit-sha"> - {{job.commit.short_id}}</a> <!-- whitespace problems --> - <copy-clipboard - title="Copy commit sha to clipboard" - :text="job.commit.short_id" - /> - <template v-if="job.merge_request"> - in - <a - class="commit-sha" - :href="job.merge_request.path"> - !{{job.merge_request.id}} - </a> - </template> - </div> - <p class="build-light-text append-bottom-0"> - {{job.pipeline.git_commit_title}} - </p> - </div> + <sidebar-artifacts :job="job" /> - <!-- tags --> - <div - v-if="job.tags.length" - class="block"> - <div class="title"> - Tags - </div> - <template v-for="tag in job.tags"> - <span class="label label-primary"> - {{tag}} - </span> - </template> - </div> + <sidebar-commit + v-if="job.commit" + :job="job" /> - <!-- stages & pipeline --> - <div - class="block" - v-if="job.details.stages.length > 1"> - <div class="title"> - Pipeline - <a - class="commit-sha" - :href="job.pipeline.path"> - #{{job.pipeline.id}} - </a> - from - <a - class="commit-sha" - :href="job.pipeline.branch"> - #{{job.pipeline.branch}} - </a> - </div> - <div class="dropdown"> - <button - type="button" - data-toggle="dropdown" - class="dropdown-menu-toggle"> - <span class="stage-selection"> - More - </span> - <i - class="fa fa-chevron-down" - aria-hidden="true"> - </i> - </button> - <ul class="dropdown-menu"> - <li v-for="stage in job.details.stages"> - <span class="stage-item">{{stage.name}}</span> - </li> - </ul> - </div> + <sidebar-tags + v-if="hasTags" + :tags="job.tags" + /> - </div> + <sidebar-stages + v-if="hasStages" + :stages="job.details.stages" + :pipeline="job.pipeline" + /> </div> - <!--related jobs --> - <div class="builds-container"> - <template v-for="relatedJob in job.relatedJobs"> - <div - class="build-job" - :class="relatedJobClassName(relatedJob)"> - - <a :href="relatedJob.path"> - <i - v-if="relatedJob.current" - class="fa fa-arrow-right" - aria-hidden="true"> - </i> - - <ci-icon :status="relatedJob.details.status" /> - - <span> - {{relatedJob.name}} - </span> - - <i - v-if="relatedJob.retried" - class="fa fa-spinner" - ref="tooltip" - title="Job was retried" - data-placement="bottom" - data-container="body"> - </i> - </a> - </div> - </template> - </div> + <sidebar-related-jobs + :related-jobs="job.relatedJobs" + v-if="hasRelatedJobs" + /> </aside> </template> diff --git a/app/assets/javascripts/jobs/components/sidebar_artifacts_block.vue b/app/assets/javascripts/jobs/components/sidebar_artifacts_block.vue new file mode 100644 index 00000000000..f4f6bc34e76 --- /dev/null +++ b/app/assets/javascripts/jobs/components/sidebar_artifacts_block.vue @@ -0,0 +1,58 @@ +<script> +import artifactsLink from './artifacts_link.vue'; +import detailRow from './sidebar_detail_row.vue'; +import timeagoMixin from '../../vue_shared/mixins/timeago'; + +export default { + name: 'SidebarArtifactsBlock', + + props: { + job: { + type: Object, + required: true, + }, + }, + + components: { + artifactsLink, + detailRow, + }, + + mixins: [timeagoMixin], + + computed: { + artifactsExpired() { + return `The artifacts were removed ${this.timeFormated(this.job.artifactsExpiredAt)}`; + }, + expiringArtifacts() { + return `The artifacts will be removed in ${this.job.artifactsExpireAt}`; + }, + }, +}; +</script> +<template> + <div class="block"> + <detail-row + v-if="job.flags.artifacts_expired" + :value="artifactsExpired" + /> + <detail-row + v-if="job.flags.has_expiring_artifacts" + :value="expiringArtifacts" + /> + <artifacts-link + v-if="job.flags.has_expiring_artifacts && job.permission.canUpdateBuild" + label="Keep" + :link="job.paths.keep" + /> + <artifacts-link + label="Download" + :link="job.paths.download" + /> + <artifacts-link + v-if="job.flags.artifacts_metadata" + label="Browse" + :link="job.paths.browse" + /> + </div> +</template> diff --git a/app/assets/javascripts/jobs/components/sidebar_commit_block.vue b/app/assets/javascripts/jobs/components/sidebar_commit_block.vue new file mode 100644 index 00000000000..1c5a6410148 --- /dev/null +++ b/app/assets/javascripts/jobs/components/sidebar_commit_block.vue @@ -0,0 +1,48 @@ +<script> +import copyClipboard from '../../vue_shared/components/copy_to_clipboard.vue'; + +export default { + name: 'SidebarCommitBlock', + + props: { + job: { + type: Object, + required: true, + }, + }, + + components: { + copyClipboard, + }, +}; +</script> +<template> + <div class="block"> + <div class="title"> + Commit + <a + :href="job.commit.commit_url" + class="commit-sha"> + {{job.commit.short_id}}</a> <!-- whitespace problems --> + + <copy-clipboard + title="Copy commit sha to clipboard" + :text="job.commit.short_id" + /> + + <template v-if="job.merge_request"> + in + <a + class="commit-sha" + :href="job.merge_request.path"> + !{{job.merge_request.id}} + </a> + </template> + + </div> + + <p class="build-light-text append-bottom-0"> + {{job.pipeline.git_commit_title}} + </p> + </div> +</template> diff --git a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue index 60f16c20be0..cf3de728182 100644 --- a/app/assets/javascripts/jobs/components/sidebar_detail_row.vue +++ b/app/assets/javascripts/jobs/components/sidebar_detail_row.vue @@ -27,7 +27,7 @@ <span v-if="hasTitle" class="build-light-text"> - {{title}} + {{title}}: </span> {{value}} </p> diff --git a/app/assets/javascripts/jobs/components/sidebar_information_block.vue b/app/assets/javascripts/jobs/components/sidebar_information_block.vue new file mode 100644 index 00000000000..3b71eebeddb --- /dev/null +++ b/app/assets/javascripts/jobs/components/sidebar_information_block.vue @@ -0,0 +1,69 @@ +<script> +import detailRow from './sidebar_detail_row.vue'; +import timeagoMixin from '../../vue_shared/mixins/timeago'; + +export default { + name: 'SidebarInformationBlock', + + props: { + job: { + type: Object, + required: true, + }, + }, + + mixins: [ + timeagoMixin, + ], + + components: { + detailRow, + }, + + computed: { + coverage() { + return `${this.job.coverage}%`; + }, + duration() { + return this.job.details.duration; + }, + queued() { + return this.job.details.queued; + }, + }, +}; +</script> +<template> + <div class="block"> + <detail-row + v-if="duration" + title="Duration" + :value="timeFormated(duration)" + /> + <detail-row + v-if="job.finishedAt" + title="Finished" + :value="timeFormated(job.finishedAt)" + /> + <detail-row + v-if="job.erasedAt" + title="Erased" + :value="timeFormated(job.erasedAt)" + /> + <detail-row + v-if="queued" + title="Queued" + :value="timeFormated(queued)" + /> + <detail-row + v-if="job.details.runner" + title="Runner" + :value="job.details.runner.id" + /> + <detail-row + v-if="job.coverage" + title="Coverage" + :value="coverage" + /> + </div> +</template> diff --git a/app/assets/javascripts/jobs/components/sidebar_related_jobs_block.vue b/app/assets/javascripts/jobs/components/sidebar_related_jobs_block.vue new file mode 100644 index 00000000000..ac239081296 --- /dev/null +++ b/app/assets/javascripts/jobs/components/sidebar_related_jobs_block.vue @@ -0,0 +1,52 @@ +<script> +import ciIcon from '../../vue_shared/components/ci_icon.vue'; + +export default { + name: 'SidebarRelatedJobsBlock', + props: { + relatedJobs: { + type: Array, + required: true, + }, + }, + + components: { + ciIcon, + }, +}; +</script> +<template> + <div class="builds-container"> + <div + v-for="relatedJob in job.relatedJobs" + class="build-job" + :class="{ + active: job.active, + retried: job.retried, + }"> + + <a :href="relatedJob.path"> + <i + v-if="relatedJob.current" + class="fa fa-arrow-right" + aria-hidden="true"> + </i> + + <ci-icon :status="relatedJob.details.status" /> + + <span> + {{relatedJob.name}} + </span> + + <i + v-if="relatedJob.retried" + class="fa fa-spinner" + ref="tooltip" + title="Job was retried" + data-placement="bottom" + data-container="body"> + </i> + </a> + </div> + </div> +</template> diff --git a/app/assets/javascripts/jobs/components/sidebar_stages_block.vue b/app/assets/javascripts/jobs/components/sidebar_stages_block.vue new file mode 100644 index 00000000000..204c3aecc51 --- /dev/null +++ b/app/assets/javascripts/jobs/components/sidebar_stages_block.vue @@ -0,0 +1,53 @@ +<script> +export default { + name: 'SidebarStagesBlock', + + props: { + stages: { + type: Array, + required: true, + }, + pipeline: { + type: Object, + required: true, + }, + }, +}; +</script> +<template> + <div class="block"> + <div class="title"> + Pipeline + <a + class="commit-sha" + :href="pipeline.path"> + #{{pipeline.id}} + </a> + from + <a + class="commit-sha" + :href="pipeline.branch"> + {{pipeline.branch}} + </a> + </div> + <div class="dropdown"> + <button + type="button" + data-toggle="dropdown" + class="dropdown-menu-toggle"> + <span class="stage-selection"> + More + </span> + <i + class="fa fa-chevron-down" + aria-hidden="true"> + </i> + </button> + <ul class="dropdown-menu"> + <li v-for="stage in stages"> + <span class="stage-item">{{stage.name}}</span> + </li> + </ul> + </div> + </div> +</template> diff --git a/app/assets/javascripts/jobs/components/sidebar_tags_block.vue b/app/assets/javascripts/jobs/components/sidebar_tags_block.vue new file mode 100644 index 00000000000..2b411c4fdf1 --- /dev/null +++ b/app/assets/javascripts/jobs/components/sidebar_tags_block.vue @@ -0,0 +1,27 @@ +<script> +/** + * Renders tags section of job's sidebar + */ +export default { + name: 'SidebarTagsBlock', + + props: { + tags: { + type: Array, + required: true, + }, + }, +}; +</script> +<template> + <div class="block"> + <div class="title"> + Tags + </div> + <span + v-for="tag in tags" + class="label label-primary"> + {{tag}} + </span> + </div> +</template> diff --git a/app/assets/javascripts/vue_shared/mixins/timeago.js b/app/assets/javascripts/vue_shared/mixins/timeago.js new file mode 100644 index 00000000000..aa95737b39e --- /dev/null +++ b/app/assets/javascripts/vue_shared/mixins/timeago.js @@ -0,0 +1,14 @@ +import '../../lib/utils/datetime_utility'; + +/** + * Mixin with time ago methods used in some vue components + */ +export default { + methods: { + timeFormated(time) { + const timeago = gl.utils.getTimeago(); + + return timeago.format(time); + }, + }, +}; diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index 6d40fe0c214..5fcb38931b4 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -348,7 +348,7 @@ text-overflow: ellipsis; &:hover { - // color: $gl-text-color; + color: $gl-text-color; } } |