diff options
author | Filipa Lacerda <filipa@gitlab.com> | 2017-05-04 18:30:41 +0000 |
---|---|---|
committer | Filipa Lacerda <filipa@gitlab.com> | 2017-05-04 18:30:41 +0000 |
commit | 7a66cd688aea6bd7d1103d0024204a1470153975 (patch) | |
tree | d3f4b3774d2b8673209304705a23462414490586 /app | |
parent | 97a9a38b689e2ff7ab6dcd04d8bae65ef778e411 (diff) | |
parent | 136baeda508ddf46f6d91c03d4128b2ee890d205 (diff) | |
download | gitlab-ce-7a66cd688aea6bd7d1103d0024204a1470153975.tar.gz |
Merge branch 'deploy-keys-load-async' into 'master'
Deploy keys load async
Closes #29667
See merge request !10973
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/deploy_keys/components/action_btn.vue | 54 | ||||
-rw-r--r-- | app/assets/javascripts/deploy_keys/components/app.vue | 102 | ||||
-rw-r--r-- | app/assets/javascripts/deploy_keys/components/key.vue | 80 | ||||
-rw-r--r-- | app/assets/javascripts/deploy_keys/components/keys_panel.vue | 52 | ||||
-rw-r--r-- | app/assets/javascripts/deploy_keys/eventhub.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/deploy_keys/index.js | 21 | ||||
-rw-r--r-- | app/assets/javascripts/deploy_keys/service/index.js | 34 | ||||
-rw-r--r-- | app/assets/javascripts/deploy_keys/store/index.js | 9 | ||||
-rw-r--r-- | app/controllers/projects/deploy_keys_controller.rb | 20 | ||||
-rw-r--r-- | app/presenters/projects/settings/deploy_keys_presenter.rb | 11 | ||||
-rw-r--r-- | app/serializers/deploy_key_entity.rb | 14 | ||||
-rw-r--r-- | app/serializers/deploy_key_serializer.rb | 3 | ||||
-rw-r--r-- | app/serializers/project_entity.rb | 14 | ||||
-rw-r--r-- | app/views/projects/deploy_keys/_index.html.haml | 23 | ||||
-rw-r--r-- | app/views/projects/settings/repository/show.html.haml | 4 |
15 files changed, 418 insertions, 26 deletions
diff --git a/app/assets/javascripts/deploy_keys/components/action_btn.vue b/app/assets/javascripts/deploy_keys/components/action_btn.vue new file mode 100644 index 00000000000..3ff3a9d977e --- /dev/null +++ b/app/assets/javascripts/deploy_keys/components/action_btn.vue @@ -0,0 +1,54 @@ +<script> + import eventHub from '../eventhub'; + + export default { + data() { + return { + isLoading: false, + }; + }, + props: { + deployKey: { + type: Object, + required: true, + }, + type: { + type: String, + required: true, + }, + btnCssClass: { + type: String, + required: false, + default: 'btn-default', + }, + }, + methods: { + doAction() { + this.isLoading = true; + + eventHub.$emit(`${this.type}.key`, this.deployKey); + }, + }, + computed: { + text() { + return `${this.type.charAt(0).toUpperCase()}${this.type.slice(1)}`; + }, + }, + }; +</script> + +<template> + <button + class="btn btn-sm prepend-left-10" + :class="[{ disabled: isLoading }, btnCssClass]" + :disabled="isLoading" + @click="doAction"> + {{ text }} + <i + v-if="isLoading" + class="fa fa-spinner fa-spin" + aria-hidden="true" + aria-label="Loading"> + </i> + </button> +</template> diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue new file mode 100644 index 00000000000..7315a9e11cb --- /dev/null +++ b/app/assets/javascripts/deploy_keys/components/app.vue @@ -0,0 +1,102 @@ +<script> + /* global Flash */ + import eventHub from '../eventhub'; + import DeployKeysService from '../service'; + import DeployKeysStore from '../store'; + import keysPanel from './keys_panel.vue'; + + export default { + data() { + return { + isLoading: false, + store: new DeployKeysStore(), + }; + }, + props: { + endpoint: { + type: String, + required: true, + }, + }, + computed: { + hasKeys() { + return Object.keys(this.keys).length; + }, + keys() { + return this.store.keys; + }, + }, + components: { + keysPanel, + }, + methods: { + fetchKeys() { + this.isLoading = true; + + this.service.getKeys() + .then((data) => { + this.isLoading = false; + this.store.keys = data; + }) + .catch(() => new Flash('Error getting deploy keys')); + }, + enableKey(deployKey) { + this.service.enableKey(deployKey.id) + .then(() => this.fetchKeys()) + .catch(() => new Flash('Error enabling deploy key')); + }, + disableKey(deployKey) { + // eslint-disable-next-line no-alert + if (confirm('You are going to remove this deploy key. Are you sure?')) { + this.service.disableKey(deployKey.id) + .then(() => this.fetchKeys()) + .catch(() => new Flash('Error removing deploy key')); + } + }, + }, + created() { + this.service = new DeployKeysService(this.endpoint); + + eventHub.$on('enable.key', this.enableKey); + eventHub.$on('remove.key', this.disableKey); + eventHub.$on('disable.key', this.disableKey); + }, + mounted() { + this.fetchKeys(); + }, + beforeDestroy() { + eventHub.$off('enable.key', this.enableKey); + eventHub.$off('remove.key', this.disableKey); + eventHub.$off('disable.key', this.disableKey); + }, + }; +</script> + +<template> + <div class="col-lg-9 col-lg-offset-3 append-bottom-default deploy-keys"> + <div + class="text-center" + v-if="isLoading && !hasKeys"> + <i + class="fa fa-spinner fa-spin fa-2x" + aria-hidden="true" + aria-label="Loading deploy keys"> + </i> + </div> + <div v-else-if="hasKeys"> + <keys-panel + title="Enabled deploy keys for this project" + :keys="keys.enabled_keys" + :store="store" /> + <keys-panel + title="Deploy keys from projects you have access to" + :keys="keys.available_project_keys" + :store="store" /> + <keys-panel + v-if="keys.public_keys.length" + title="Public deploy keys available to any project" + :keys="keys.public_keys" + :store="store" /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/deploy_keys/components/key.vue b/app/assets/javascripts/deploy_keys/components/key.vue new file mode 100644 index 00000000000..0a06a481b96 --- /dev/null +++ b/app/assets/javascripts/deploy_keys/components/key.vue @@ -0,0 +1,80 @@ +<script> + import actionBtn from './action_btn.vue'; + + export default { + props: { + deployKey: { + type: Object, + required: true, + }, + store: { + type: Object, + required: true, + }, + }, + components: { + actionBtn, + }, + computed: { + timeagoDate() { + return gl.utils.getTimeago().format(this.deployKey.created_at); + }, + }, + methods: { + isEnabled(id) { + return this.store.findEnabledKey(id) !== undefined; + }, + }, + }; +</script> + +<template> + <div> + <div class="pull-left append-right-10 hidden-xs"> + <i + aria-hidden="true" + class="fa fa-key key-icon"> + </i> + </div> + <div class="deploy-key-content key-list-item-info"> + <strong class="title"> + {{ deployKey.title }} + </strong> + <div class="description"> + {{ deployKey.fingerprint }} + </div> + <div + v-if="deployKey.can_push" + class="write-access-allowed"> + Write access allowed + </div> + </div> + <div class="deploy-key-content prepend-left-default deploy-key-projects"> + <a + v-for="project in deployKey.projects" + class="label deploy-project-label" + :href="project.full_path"> + {{ project.full_name }} + </a> + </div> + <div class="deploy-key-content"> + <span class="key-created-at"> + created {{ timeagoDate }} + </span> + <action-btn + v-if="!isEnabled(deployKey.id)" + :deploy-key="deployKey" + type="enable"/> + <action-btn + v-else-if="deployKey.destroyed_when_orphaned && deployKey.almost_orphaned" + :deploy-key="deployKey" + btn-css-class="btn-warning" + type="remove" /> + <action-btn + v-else + :deploy-key="deployKey" + btn-css-class="btn-warning" + type="disable" /> + </div> + </div> +</template> diff --git a/app/assets/javascripts/deploy_keys/components/keys_panel.vue b/app/assets/javascripts/deploy_keys/components/keys_panel.vue new file mode 100644 index 00000000000..eccc470578b --- /dev/null +++ b/app/assets/javascripts/deploy_keys/components/keys_panel.vue @@ -0,0 +1,52 @@ +<script> + import key from './key.vue'; + + export default { + props: { + title: { + type: String, + required: true, + }, + keys: { + type: Array, + required: true, + }, + showHelpBox: { + type: Boolean, + required: false, + default: true, + }, + store: { + type: Object, + required: true, + }, + }, + components: { + key, + }, + }; +</script> + +<template> + <div class="deploy-keys-panel"> + <h5> + {{ title }} + ({{ keys.length }}) + </h5> + <ul class="well-list" + v-if="keys.length"> + <li + v-for="deployKey in keys" + :key="deployKey.id"> + <key + :deploy-key="deployKey" + :store="store" /> + </li> + </ul> + <div + class="settings-message text-center" + v-else-if="showHelpBox"> + No deploy keys found. Create one with the form above. + </div> + </div> +</template> diff --git a/app/assets/javascripts/deploy_keys/eventhub.js b/app/assets/javascripts/deploy_keys/eventhub.js new file mode 100644 index 00000000000..0948c2e5352 --- /dev/null +++ b/app/assets/javascripts/deploy_keys/eventhub.js @@ -0,0 +1,3 @@ +import Vue from 'vue'; + +export default new Vue(); diff --git a/app/assets/javascripts/deploy_keys/index.js b/app/assets/javascripts/deploy_keys/index.js new file mode 100644 index 00000000000..a5f232f950a --- /dev/null +++ b/app/assets/javascripts/deploy_keys/index.js @@ -0,0 +1,21 @@ +import Vue from 'vue'; +import deployKeysApp from './components/app.vue'; + +document.addEventListener('DOMContentLoaded', () => new Vue({ + el: document.getElementById('js-deploy-keys'), + data() { + return { + endpoint: this.$options.el.dataset.endpoint, + }; + }, + components: { + deployKeysApp, + }, + render(createElement) { + return createElement('deploy-keys-app', { + props: { + endpoint: this.endpoint, + }, + }); + }, +})); diff --git a/app/assets/javascripts/deploy_keys/service/index.js b/app/assets/javascripts/deploy_keys/service/index.js new file mode 100644 index 00000000000..fe6dbaa9498 --- /dev/null +++ b/app/assets/javascripts/deploy_keys/service/index.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import VueResource from 'vue-resource'; + +Vue.use(VueResource); + +export default class DeployKeysService { + constructor(endpoint) { + this.endpoint = endpoint; + + this.resource = Vue.resource(`${this.endpoint}{/id}`, {}, { + enable: { + method: 'PUT', + url: `${this.endpoint}{/id}/enable`, + }, + disable: { + method: 'PUT', + url: `${this.endpoint}{/id}/disable`, + }, + }); + } + + getKeys() { + return this.resource.get() + .then(response => response.json()); + } + + enableKey(id) { + return this.resource.enable({ id }, {}); + } + + disableKey(id) { + return this.resource.disable({ id }, {}); + } +} diff --git a/app/assets/javascripts/deploy_keys/store/index.js b/app/assets/javascripts/deploy_keys/store/index.js new file mode 100644 index 00000000000..6210361af26 --- /dev/null +++ b/app/assets/javascripts/deploy_keys/store/index.js @@ -0,0 +1,9 @@ +export default class DeployKeysStore { + constructor() { + this.keys = {}; + } + + findEnabledKey(id) { + return this.keys.enabled_keys.find(key => key.id === id); + } +} diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb index d0c44e297e3..f27089b8590 100644 --- a/app/controllers/projects/deploy_keys_controller.rb +++ b/app/controllers/projects/deploy_keys_controller.rb @@ -8,7 +8,12 @@ class Projects::DeployKeysController < Projects::ApplicationController layout "project_settings" def index - redirect_to_repository_settings(@project) + respond_to do |format| + format.html { redirect_to_repository_settings(@project) } + format.json do + render json: Projects::Settings::DeployKeysPresenter.new(@project, current_user: current_user).as_json + end + end end def new @@ -19,7 +24,7 @@ class Projects::DeployKeysController < Projects::ApplicationController @key = DeployKey.new(deploy_key_params.merge(user: current_user)) unless @key.valid? && @project.deploy_keys << @key - flash[:alert] = @key.errors.full_messages.join(', ').html_safe + flash[:alert] = @key.errors.full_messages.join(', ').html_safe end redirect_to_repository_settings(@project) end @@ -27,7 +32,10 @@ class Projects::DeployKeysController < Projects::ApplicationController def enable Projects::EnableDeployKeyService.new(@project, current_user, params).execute - redirect_to_repository_settings(@project) + respond_to do |format| + format.html { redirect_to_repository_settings(@project) } + format.json { head :ok } + end end def disable @@ -35,7 +43,11 @@ class Projects::DeployKeysController < Projects::ApplicationController return render_404 unless deploy_key_project deploy_key_project.destroy! - redirect_to_repository_settings(@project) + + respond_to do |format| + format.html { redirect_to_repository_settings(@project) } + format.json { head :ok } + end end protected diff --git a/app/presenters/projects/settings/deploy_keys_presenter.rb b/app/presenters/projects/settings/deploy_keys_presenter.rb index 86ac513b3c0..070b0c35e36 100644 --- a/app/presenters/projects/settings/deploy_keys_presenter.rb +++ b/app/presenters/projects/settings/deploy_keys_presenter.rb @@ -48,6 +48,17 @@ module Projects available_public_keys.any? end + def as_json + serializer = DeployKeySerializer.new + opts = { user: current_user } + + { + enabled_keys: serializer.represent(enabled_keys, opts), + available_project_keys: serializer.represent(available_project_keys, opts), + public_keys: serializer.represent(available_public_keys, opts) + } + end + def to_partial_path 'projects/deploy_keys/index' end diff --git a/app/serializers/deploy_key_entity.rb b/app/serializers/deploy_key_entity.rb new file mode 100644 index 00000000000..d75a83d0fa5 --- /dev/null +++ b/app/serializers/deploy_key_entity.rb @@ -0,0 +1,14 @@ +class DeployKeyEntity < Grape::Entity + expose :id + expose :user_id + expose :title + expose :fingerprint + expose :can_push + expose :destroyed_when_orphaned?, as: :destroyed_when_orphaned + expose :almost_orphaned?, as: :almost_orphaned + expose :created_at + expose :updated_at + expose :projects, using: ProjectEntity do |deploy_key| + deploy_key.projects.select { |project| options[:user].can?(:read_project, project) } + end +end diff --git a/app/serializers/deploy_key_serializer.rb b/app/serializers/deploy_key_serializer.rb new file mode 100644 index 00000000000..8f849eb88b7 --- /dev/null +++ b/app/serializers/deploy_key_serializer.rb @@ -0,0 +1,3 @@ +class DeployKeySerializer < BaseSerializer + entity DeployKeyEntity +end diff --git a/app/serializers/project_entity.rb b/app/serializers/project_entity.rb new file mode 100644 index 00000000000..a471a7e6a88 --- /dev/null +++ b/app/serializers/project_entity.rb @@ -0,0 +1,14 @@ +class ProjectEntity < Grape::Entity + include RequestAwareEntity + + expose :id + expose :name + + expose :full_path do |project| + namespace_project_path(project.namespace, project) + end + + expose :full_name do |project| + project.full_name + end +end diff --git a/app/views/projects/deploy_keys/_index.html.haml b/app/views/projects/deploy_keys/_index.html.haml index 4cfbd9add00..74756b58439 100644 --- a/app/views/projects/deploy_keys/_index.html.haml +++ b/app/views/projects/deploy_keys/_index.html.haml @@ -10,25 +10,4 @@ = render @deploy_keys.form_partial_path .col-lg-9.col-lg-offset-3 %hr - .col-lg-9.col-lg-offset-3.append-bottom-default.deploy-keys - %h5.prepend-top-0 - Enabled deploy keys for this project (#{@deploy_keys.enabled_keys_size}) - - if @deploy_keys.any_keys_enabled? - %ul.well-list - = render partial: 'projects/deploy_keys/deploy_key', collection: @deploy_keys.enabled_keys, as: :deploy_key - - else - .settings-message.text-center - No deploy keys found. Create one with the form above. - %h5.prepend-top-default - Deploy keys from projects you have access to (#{@deploy_keys.available_project_keys_size}) - - if @deploy_keys.any_available_project_keys_enabled? - %ul.well-list - = render partial: 'projects/deploy_keys/deploy_key', collection: @deploy_keys.available_project_keys, as: :deploy_key - - else - .settings-message.text-center - No deploy keys from your projects could be found. Create one with the form above or add existing one below. - - if @deploy_keys.any_available_public_keys_enabled? - %h5.prepend-top-default - Public deploy keys available to any project (#{@deploy_keys.available_public_keys_size}) - %ul.well-list - = render partial: 'projects/deploy_keys/deploy_key', collection: @deploy_keys.available_public_keys, as: :deploy_key + #js-deploy-keys{ data: { endpoint: namespace_project_deploy_keys_path } } diff --git a/app/views/projects/settings/repository/show.html.haml b/app/views/projects/settings/repository/show.html.haml index 5402320cb66..4e59033c4a3 100644 --- a/app/views/projects/settings/repository/show.html.haml +++ b/app/views/projects/settings/repository/show.html.haml @@ -1,6 +1,10 @@ - page_title "Repository" = render "projects/settings/head" +- content_for :page_specific_javascripts do + = page_specific_javascript_bundle_tag('common_vue') + = page_specific_javascript_bundle_tag('deploy_keys') + = render @deploy_keys = render "projects/protected_branches/index" = render "projects/protected_tags/index" |