summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Hughes <me@iamphill.com>2017-04-28 17:06:19 +0100
committerPhil Hughes <me@iamphill.com>2017-04-28 17:06:19 +0100
commite11a702afceee7f5edeb8c93a4192fa05209b091 (patch)
treeecb9cea80803638c9b8878b091793beb3ed88720
parent79e2a524e22e5474c5b33deb81ac6cc51512d2e5 (diff)
downloadgitlab-ce-e11a702afceee7f5edeb8c93a4192fa05209b091.tar.gz
Re-wrote to match our docs - still not 100% sure but closer than it was
-rw-r--r--app/assets/javascripts/deploy_keys/components/action_btn.vue53
-rw-r--r--app/assets/javascripts/deploy_keys/components/app.vue105
-rw-r--r--app/assets/javascripts/deploy_keys/components/key.vue85
-rw-r--r--app/assets/javascripts/deploy_keys/components/keys.vue52
-rw-r--r--app/assets/javascripts/deploy_keys/eventhub.js3
-rw-r--r--app/assets/javascripts/deploy_keys/index.js21
-rw-r--r--app/assets/javascripts/deploy_keys/service/index.js34
-rw-r--r--app/assets/javascripts/deploy_keys/store/index.js13
-rw-r--r--app/assets/javascripts/dispatcher.js3
-rw-r--r--app/assets/javascripts/settings/settings_repository.js96
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb11
-rw-r--r--app/serializers/project_entity.rb4
-rw-r--r--app/views/projects/deploy_keys/_index.html.haml14
-rw-r--r--app/views/projects/settings/repository/show.html.haml4
-rw-r--r--config/webpack.config.js1
15 files changed, 384 insertions, 115 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..7da2915a45e
--- /dev/null
+++ b/app/assets/javascripts/deploy_keys/components/action_btn.vue
@@ -0,0 +1,53 @@
+<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">
+ </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..ff54a0f241a
--- /dev/null
+++ b/app/assets/javascripts/deploy_keys/components/app.vue
@@ -0,0 +1,105 @@
+<script>
+ /* global Flash */
+ import eventHub from '../eventhub';
+ import DeployKeysService from '../service';
+ import DeployKeysStore from '../store';
+ import keysPanel from './keys.vue';
+
+ export default {
+ data() {
+ const store = new DeployKeysStore();
+
+ return {
+ isLoading: false,
+ store,
+ };
+ },
+ 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.store.keys = {};
+
+ 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'));
+ },
+ removeKey(deployKey) {
+ this.disableKey(deployKey);
+ },
+ 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.removeKey);
+ eventHub.$on('disable.key', this.disableKey);
+ },
+ mounted() {
+ this.fetchKeys();
+ },
+ beforeDestroy() {
+ eventHub.$off('enable.key', this.enableKey);
+ eventHub.$off('remove.key', this.removeKey);
+ eventHub.$off('disable.key', this.disableKey);
+ },
+ };
+</script>
+
+<template>
+ <div class="col-lg-9 col-lg-offset-3 append-bottom-default">
+ <div
+ class="text-center"
+ v-if="isLoading && !hasKeys">
+ <i
+ class="fa fa-spinner fa-spin fa-2x">
+ </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
+ 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..af842a3bb39
--- /dev/null
+++ b/app/assets/javascripts/deploy_keys/components/key.vue
@@ -0,0 +1,85 @@
+<script>
+ import actionBtn from './action_btn.vue';
+
+ export default {
+ props: {
+ deployKey: {
+ type: Object,
+ required: true,
+ },
+ enabled: {
+ type: Boolean,
+ required: false,
+ default: 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
+ class="label deploy-project-label"
+ :href="project.full_path"
+ v-for="project in deployKey.projects">
+ {{ 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.vue b/app/assets/javascripts/deploy_keys/components/keys.vue
new file mode 100644
index 00000000000..2470831eddf
--- /dev/null
+++ b/app/assets/javascripts/deploy_keys/components/keys.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>
+ <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..7177d9bed7f
--- /dev/null
+++ b/app/assets/javascripts/deploy_keys/store/index.js
@@ -0,0 +1,13 @@
+export default class DeployKeysStore {
+ constructor() {
+ this.keys = {};
+ }
+
+ findEnabledKey(id) {
+ return this.keys.enabled_keys.find(key => key.id === id);
+ }
+
+ removeKeyForType(deployKey, type) {
+ this.keys[type] = this.keys[type].filter(key => key.id !== deployKey.id);
+ }
+}
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index f7402792c59..d3d75c4bf4a 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -48,7 +48,6 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
import UserCallout from './user_callout';
import { ProtectedTagCreate, ProtectedTagEditList } from './protected_tags';
import ShortcutsWiki from './shortcuts_wiki';
-import SettingsDeployKeys from './settings/settings_repository';
import BlobViewer from './blob/viewer/index';
const ShortcutsBlob = require('./shortcuts_blob');
@@ -346,8 +345,6 @@ const ShortcutsBlob = require('./shortcuts_blob');
// Initialize Protected Tag Settings
new ProtectedTagCreate();
new ProtectedTagEditList();
- // Initialize deploy key ajax call
- new SettingsDeployKeys();
break;
case 'projects:ci_cd:show':
new gl.ProjectVariables();
diff --git a/app/assets/javascripts/settings/settings_repository.js b/app/assets/javascripts/settings/settings_repository.js
deleted file mode 100644
index 9d6a60baa3a..00000000000
--- a/app/assets/javascripts/settings/settings_repository.js
+++ /dev/null
@@ -1,96 +0,0 @@
-/* eslint-disable no-new */
-import Vue from 'vue';
-import VueResource from 'vue-resource';
-
-Vue.use(VueResource);
-
-export default class SettingsDeployKeys {
- constructor() {
- this.initVue();
- }
-
- deployKeyRowTemplate() {
- return `
- <li>
- <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>
- <div class="deploy-key-content prepend-left-default deploy-key-projects">
- <a class="label deploy-project-label" :href="project.full_path" v-for="project in deployKey.projects">{{project.full_name}}</a>
- </div>
- <div class="deploy-key-content">
- <span class="key-created-at">
- created {{timeagoDate}}
- </span>
- <div class="visible-xs-block visible-sm-block"></div>
- <a v-if="!enabled" class="btn btn-sm prepend-left-10" rel="nofollow" data-method="put" href="enableURL">Enable
-</a>
- <a v-else-if="deployKey.destroyed_when_orphaned && deployKey.almost_orphaned" class="btn btn-warning btn-sm prepend-left-10" rel="nofollow" data-method="put" :href="disableURL">Remove</a>
- <a v-else class="btn btn-warning btn-sm prepend-left-10" rel="nofollow" data-method="put" :href="disableURL">Disable</a>
- </div>
- </li>`
- }
-
- deployKeyRowComponent() {
- const self = this;
- return {
- props: {
- deployKey: Object,
- enabled: Boolean
- },
-
- computed: {
- timeagoDate() {
- return gl.utils.getTimeago().format(this.deployKey.createdAt, 'gl_en');
- },
-
- disableURL() {
- return self.disableEndpoint.replace(':id', this.deployKey.id);
- },
-
- enableURL() {
- return self.enableEndpoint.replace(':id', this.deployKey.id);
- }
- },
-
- template: this.deployKeyRowTemplate()
- }
- }
-
- initVue() {
- const self = this;
- const el = document.getElementById('js-deploy-keys');
- const endpoint = el.dataset.endpoint;
- this.jsonEndpoint = `${endpoint}.json`;
- this.disableEndpoint = `${endpoint}/:id/disable`;
- this.enableEndpoint = `${endpoint}/:id/enable`;
- new Vue({
- el: el,
- components: {
- deployKeyRow: self.deployKeyRowComponent()
- },
- data () {
- return {
- enabledKeys: [],
- availableKeys: []
- }
- },
- created () {
- this.$http.get(self.jsonEndpoint)
- .then((res) => {
- const keys = JSON.parse(res.body);
- this.enabledKeys = keys.enabled_keys;
- this.availableKeys = keys.available_project_keys;
- });
- }
- })
- }
-} \ No newline at end of file
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index a47e15a192b..f27089b8590 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -32,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
@@ -40,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/serializers/project_entity.rb b/app/serializers/project_entity.rb
index 6f8061f7530..a471a7e6a88 100644
--- a/app/serializers/project_entity.rb
+++ b/app/serializers/project_entity.rb
@@ -1,9 +1,11 @@
class ProjectEntity < Grape::Entity
+ include RequestAwareEntity
+
expose :id
expose :name
expose :full_path do |project|
- project.full_path
+ namespace_project_path(project.namespace, project)
end
expose :full_name do |project|
diff --git a/app/views/projects/deploy_keys/_index.html.haml b/app/views/projects/deploy_keys/_index.html.haml
index b35cd356aa5..74756b58439 100644
--- a/app/views/projects/deploy_keys/_index.html.haml
+++ b/app/views/projects/deploy_keys/_index.html.haml
@@ -10,16 +10,4 @@
= render @deploy_keys.form_partial_path
.col-lg-9.col-lg-offset-3
%hr
- #js-deploy-keys.col-lg-9.col-lg-offset-3.append-bottom-default{data:{endpoint: namespace_project_deploy_keys_path}}
- %h5.prepend-top-0
- Enabled deploy keys for this project ({{enabledKeys.length}})
- %ul.well-list{"v-if" => "enabledKeys.length"}
- %deploy-key-row{"v-for" => "deployKey in enabledKeys", ":deploy-key" => "deployKey", ":enabled" =>"true"}
- .settings-message.text-center{"v-else" => true}
- No deploy keys found. Create one with the form above.
- %h5.prepend-top-0
- Deploy keys from projects you have access to ({{availableKeys.length}})
- %ul.well-list{"v-if" => "availableKeys.length"}
- %deploy-key-row{"v-for" => "deployKey in availableKeys", ":deploy-key" => "deployKey", ":enabled" =>"false"}
- .settings-message.text-center{"v-else" => true}
- No deploy keys found. Create one with the form above.
+ #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"
diff --git a/config/webpack.config.js b/config/webpack.config.js
index cb0a57a3a41..1721d275685 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -26,6 +26,7 @@ var config = {
common_d3: ['d3'],
cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js',
commit_pipelines: './commit/pipelines/pipelines_bundle.js',
+ deploy_keys: './deploy_keys/index.js',
diff_notes: './diff_notes/diff_notes_bundle.js',
environments: './environments/environments_bundle.js',
environments_folder: './environments/folder/environments_folder_bundle.js',