diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2018-10-22 08:31:24 +0000 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2018-10-22 08:31:24 +0000 |
commit | 25170fbe7b004e368d68c3b73be9232611bda48d (patch) | |
tree | c1db004b8a9960da7a6bd2599e22f364a7ba966c /app | |
parent | 1438e322a5cb7f3207d64f35d873db8a160cde94 (diff) | |
download | gitlab-ce-25170fbe7b004e368d68c3b73be9232611bda48d.tar.gz |
Frontend: Review app changes
Diffstat (limited to 'app')
5 files changed, 219 insertions, 24 deletions
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue index 9161f703697..6c87287a4c4 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment.vue @@ -1,6 +1,7 @@ <script> import Icon from '~/vue_shared/components/icon.vue'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; +import FilteredSearchDropdown from '~/vue_shared/components/filtered_search_dropdown.vue'; import timeagoMixin from '../../vue_shared/mixins/timeago'; import tooltip from '../../vue_shared/directives/tooltip'; import LoadingButton from '../../vue_shared/components/loading_button.vue'; @@ -18,6 +19,7 @@ export default { StatusIcon, Icon, TooltipOnTruncate, + FilteredSearchDropdown, }, directives: { tooltip, @@ -30,8 +32,10 @@ export default { }, }, data() { + const features = window.gon.features || {}; return { isStopping: false, + enableCiEnvironmentsStatusChanges: features.ciEnvironmentsStatusChanges, }; }, computed: { @@ -118,18 +122,65 @@ export default { /> </div> <div> - <a - v-if="hasExternalUrls" - :href="deployment.external_url" - target="_blank" - rel="noopener noreferrer nofollow" - class="deploy-link js-deploy-url btn btn-default btn-sm inline" - > - <span> - View app - <icon name="external-link" /> - </span> - </a> + <template v-if="hasExternalUrls"> + <filtered-search-dropdown + v-if="enableCiEnvironmentsStatusChanges" + class="js-mr-wigdet-deployment-dropdown inline" + :items="deployment.changes" + :main-action-link="deployment.external_url" + filter-key="path" + > + <template + slot="mainAction" + slot-scope="slotProps" + > + <a + :href="deployment.external_url" + target="_blank" + rel="noopener noreferrer nofollow" + class="deploy-link js-deploy-url inline" + :class="slotProps.className" + > + <span> + {{ __('View app') }} + <icon name="external-link" /> + </span> + </a> + </template> + + <template + slot="result" + slot-scope="slotProps" + > + <a + :href="slotProps.result.external_url" + target="_blank" + rel="noopener noreferrer nofollow" + class="menu-item" + > + <strong class="str-truncated-100 append-bottom-0 d-block"> + {{ slotProps.result.path }} + </strong> + + <p class="text-secondary str-truncated-100 append-bottom-0 d-block"> + {{ slotProps.result.external_url }} + </p> + </a> + </template> + </filtered-search-dropdown> + <a + v-else + :href="deployment.external_url" + target="_blank" + rel="noopener noreferrer nofollow" + class="js-deploy-url js-deploy-url-feature-flag deploy-link btn btn-default btn-sm inline" + > + <span> + {{ __('View app') }} + <icon name="external-link" /> + </span> + </a> + </template> <loading-button v-if="deployment.stop_url" :loading="isStopping" diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index a599cc002d6..8180f13a7cb 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -112,7 +112,8 @@ export default { eventHub.$on('mr.discussion.updated', this.checkStatus); }, mounted() { - this.handleMounted(); + this.setFaviconHelper(); + this.initDeploymentsPolling(); }, beforeDestroy() { eventHub.$off('mr.discussion.updated', this.checkStatus); @@ -250,10 +251,6 @@ export default { this.stopPolling(); }); }, - handleMounted() { - this.setFaviconHelper(); - this.initDeploymentsPolling(); - }, }, }; </script> diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue new file mode 100644 index 00000000000..460fa6ad72e --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/filtered_search_dropdown.vue @@ -0,0 +1,143 @@ +<script> +import $ from 'jquery'; +import Icon from '~/vue_shared/components/icon.vue'; +/** + * Renders a split dropdown with + * an input that allows to search through the given + * array of options. + */ +export default { + name: 'FilteredSearchDropdown', + components: { + Icon, + }, + props: { + title: { + type: String, + required: false, + default: '', + }, + buttonType: { + required: false, + validator: value => + ['primary', 'default', 'secondary', 'success', 'info', 'warning', 'danger'].indexOf( + value, + ) !== -1, + default: 'default', + }, + size: { + required: false, + type: String, + default: 'sm', + }, + items: { + type: Array, + required: true, + }, + visibleItems: { + type: Number, + required: false, + default: 5, + }, + filterKey: { + type: String, + required: true, + }, + }, + data() { + return { + filter: '', + }; + }, + computed: { + className() { + return `btn btn-${this.buttonType} btn-${this.size}`; + }, + filteredResults() { + if (this.filter !== '') { + return this.items.filter( + item => item[this.filterKey] && item[this.filterKey].toLowerCase().includes(this.filter.toLowerCase()), + ); + } + + return this.items.slice(0, this.visibleItems); + } + }, + mounted() { + /** + * Resets the filter every time the user closes the dropdown + */ + $(this.$el) + .on('shown.bs.dropdown', () => { + this.$nextTick(() => this.$refs.searchInput.focus()); + }) + .on('hidden.bs.dropdown', () => { + this.filter = ''; + }); + }, +}; +</script> +<template> + <div class="dropdown"> + <div class="btn-group"> + <slot + name="mainAction" + :class-name="className" + > + <button + type="button" + :class="className" + > + {{ title }} + </button> + </slot> + + <button + type="button" + :class="className" + class="dropdown-toggle dropdown-toggle-split" + data-toggle="dropdown" + aria-haspopup="true" + aria-expanded="false" + aria-label="Expand dropdown" + > + <icon + name="angle-down" + :size="12" + /> + </button> + <div class="dropdown-menu dropdown-menu-right"> + <div class="dropdown-input"> + <input + ref="searchInput" + v-model="filter" + type="search" + placeholder="Filter" + class="js-filtered-dropdown-input dropdown-input-field" + /> + <icon + class="dropdown-input-search" + name="search" + /> + </div> + + <div class="dropdown-content"> + <ul> + <li + v-for="(result, i) in filteredResults" + :key="i" + class="js-filtered-dropdown-result" + > + <slot + name="result" + :result="result" + > + {{ result[filterKey] }} + </slot> + </li> + </ul> + </div> + </div> + </div> + </div> +</template> diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 895db89f289..2feb7464ecb 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -47,7 +47,6 @@ } } - .mr-widget-heading { position: relative; border: 1px solid $border-color; @@ -454,7 +453,7 @@ .mr-list { .merge-request { - padding: 10px 0 10px 15px; + padding: 10px 0 10px 15px; position: relative; display: -webkit-flex; display: flex; @@ -468,7 +467,6 @@ margin-bottom: 2px; .ci-status-link { - svg { height: 16px; width: 16px; @@ -698,7 +696,6 @@ .table-holder { .ci-table { - th { background-color: $white-light; color: $gl-text-color-secondary; @@ -775,7 +772,7 @@ &.affix { left: 0; - transition: right .15s; + transition: right 0.15s; @include media-breakpoint-down(xs) { right: 0; @@ -884,7 +881,7 @@ } > *:not(:last-child) { - margin-right: .3em; + margin-right: 0.3em; } svg { @@ -907,6 +904,10 @@ .btn svg { fill: $theme-gray-700; } + + .dropdown-menu { + width: 400px; + } } // Hack alert: we've rewritten `btn` class in a way that @@ -917,7 +918,7 @@ &[disabled] { cursor: not-allowed; box-shadow: none; - opacity: .65; + opacity: 0.65; &:hover { color: $gl-gray-500; diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index f87337b67aa..757b03d0b0e 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -14,6 +14,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo before_action :set_issuables_index, only: [:index] before_action :authenticate_user!, only: [:assign_related_issues] before_action :check_user_can_push_to_source_branch!, only: [:rebase] + before_action do + push_frontend_feature_flag(:ci_environments_status_changes) + end def index @merge_requests = @issuables |