summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2017-09-19 16:38:55 +0100
committerFilipa Lacerda <filipa@gitlab.com>2017-09-19 17:55:25 +0100
commit51c9f8b6d681412166aaefccd36c589401ed89b5 (patch)
tree9f0612adbbaa0a56fb8b4554a2e42ac9c3e4fb12 /app
parent23024a70dbc50dbd0114ed715c906cac1a9b1d59 (diff)
downloadgitlab-ce-51c9f8b6d681412166aaefccd36c589401ed89b5.tar.gz
[ci skip] First iteration: port haml into vue
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/registry/components/app.vue90
-rw-r--r--app/assets/javascripts/registry/components/collapsible_container.vue137
-rw-r--r--app/assets/javascripts/registry/constants.js13
-rw-r--r--app/assets/javascripts/registry/index.js25
-rw-r--r--app/assets/javascripts/registry/stores/actions.js11
-rw-r--r--app/assets/javascripts/registry/stores/getters.js2
-rw-r--r--app/assets/javascripts/registry/stores/index.js8
-rw-r--r--app/assets/javascripts/registry/stores/mutation_types.js5
-rw-r--r--app/assets/javascripts/registry/stores/mutations.js41
-rw-r--r--app/assets/javascripts/vue_shared/components/clipboard_button.vue10
-rw-r--r--app/assets/stylesheets/pages/container_registry.scss4
-rw-r--r--app/controllers/projects/registry/repositories_controller.rb31
-rw-r--r--app/views/projects/registry/repositories/index.html.haml18
13 files changed, 320 insertions, 75 deletions
diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue
index e69de29bb2d..17a57ae248d 100644
--- a/app/assets/javascripts/registry/components/app.vue
+++ b/app/assets/javascripts/registry/components/app.vue
@@ -0,0 +1,90 @@
+<script>
+ /* globals Flash */
+ import { mapGetters, mapActions } from 'vuex';
+ import '../../flash';
+ import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+ import store from '../stores';
+ import collapsibleContainer from './collapsible_container.vue';
+ import { errorMessages, errorMessagesTypes } from '../constants';
+
+ export default {
+ name: 'registryListApp',
+ props: {
+ endpoint: {
+ type: String,
+ required: true
+ },
+ },
+ store,
+ components: {
+ collapsibleContainer,
+ loadingIcon,
+ },
+ computed: {
+ ...mapGetters([
+ 'isLoading',
+ 'repos',
+ ]),
+ },
+ methods: {
+ ...mapActions([
+ 'setMainEndpoint',
+ 'fetchRepos',
+ 'fetchList',
+ 'deleteRepo',
+ 'deleteRegistry',
+ 'toggleIsLoading',
+ ]),
+
+ fetchRegistryList(repo) {
+ this.fetchList(repo)
+ .catch(() => this.showError(errorMessagesTypes.FETCH_REGISTRY))
+ },
+
+ deleteRegistry(repo, registry) {
+ this.deleteRegistry(registry)
+ .then(() => this.fetchRegistry(repo))
+ .catch(() => this.showError(errorMessagesTypes.DELETE_REGISTRY));
+ },
+
+ deleteRepository(repo) {
+ this.deleteRepo(repo)
+ .then(() => this.fetchRepo())
+ .catch(() => this.showError(errorMessagesTypes.DELETE_REPO));
+ },
+
+ showError(message){
+ Flash(__(errorMessages[message]));
+ }
+ },
+ created() {
+ this.setMainEndpoint(this.endpoint);
+ },
+ mounted() {
+ this.fetchRepos()
+ .catch(() => this.showError(errorMessagesTypes.FETCH_REPOS));
+ }
+ };
+</script>
+<template>
+ <div>
+ <loading-icon
+ v-if="isLoading"
+ size="3"
+ />
+
+ <collapsible-container
+ v-else-if="!isLoading && repos.length"
+ v-for="(item, index) in repos"
+ :key="index"
+ :repo="item"
+ @fetchRegistryList="fetchRegistryList"
+ @deleteRepository="deleteRepository"
+ @deleteRegistry="deleteRegistry"
+ />
+
+ <p v-else-if="!isLoading && !repos.length">
+ {{__("No container images stored for this project. Add one by following the instructions above")}}
+ </p>
+ </div>
+</template>
diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue
index 20ebedd2b45..6be2aa60ebd 100644
--- a/app/assets/javascripts/registry/components/collapsible_container.vue
+++ b/app/assets/javascripts/registry/components/collapsible_container.vue
@@ -1,24 +1,22 @@
<script>
import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
+ import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+ import tooltip from '../../vue_shared/directives/tooltip';
export default {
name: 'collapsibeContainerRegisty',
props: {
- title: {
- type: String,
- required: true,
- },
- clipboardContent: {
- type: String,
- required: true,
- },
- repoData: {
+ repo: {
type: Object,
required: true,
},
},
components: {
clipboardButton,
+ loadingIcon,
+ },
+ directives: {
+ tooltip,
},
data() {
return {
@@ -26,37 +24,73 @@
};
},
methods: {
- itemSize(item) {
+ layers(item) {
const pluralize = gl.text.pluralize('layer', item.layers);
- return `${item.size}&middot;${item.layers}${pluralize}`;
- }
- }
- }
+ return `${item.layers} ${pluralize}`;
+ },
+ toggleRepo() {
+ if (this.isOpen === false) {
+ // consider not fetching data the second time it is toggled? :fry:
+ this.$emit('fetchRegistryList', this.repo);
+ }
+ this.isOpen = !this.isOpen;
+ },
+ handleDeleteRepository() {
+ this.$emit('deleteRepository', this.repo)
+ },
+ handleDeleteRegistry(registry) {
+ this.$emit('deleteRegistry', this.repo, registry);
+ },
+ },
+ };
</script>
<template>
<div class="container-image">
- <div class="container-image-head">
- <i
- class="fa"
- :class="{
- 'chevron-left': !isOpen,
- 'chevron-up': isOpen,
- }"
- aria-hidden="true">
- </i>
- {{title}}
+ <div
+ class="container-image-head">
+ <a
+ role="button"
+ @click="toggleRepo">
+ <i
+ class="fa"
+ :class="{
+ 'fa-chevron-right': !isOpen,
+ 'fa-chevron-up': isOpen,
+ }"
+ aria-hidden="true">
+ </i>
+ {{repo.name}}
+ </a>
+
+ <clipboard-button text="foo" title="bar" />
+
+ <div class="controls hidden-xs pull-right">
+ <button
+ v-if="repo.canDelete"
+ type="button"
+ class="btn btn-remove"
+ :title="__('Remove repository')"
+ v-tooltip
+ @click="handleDeleteRepository">
+ <i
+ class="fa fa-trash"
+ aria-hidden="true">
+ </i>
+ </button>
+ </div>
- <clipboard-button
- :text=""
- :title=""
- />
</div>
+
+ <loading-icon
+ v-if="repo.isLoading"
+ />
+
<div
- class="container-image-tags"
- :class="{ hide: !isOpen }">
+ v-else-if="!repo.isLoading && isOpen"
+ class="container-image-tags">
- <table class="table tags" v-if="true">
+ <table class="table tags" v-if="repo.list.length">
<thead>
<tr>
<th>{{__("Tag")}}</th>
@@ -71,23 +105,28 @@
v-for="(item, i) in repo.list"
:key="i">
<td>
- {{item.name}}
+
+ {{item.tag}}
+
<clipboard-button
- :title="item.location"
- :text="item.location"
+ :title="item.tag"
+ :text="item.tag"
/>
</td>
<td>
<span
v-tooltip
:title="item.revision"
+ data-placement="bottom"
>
{{item.shortRevision}}
</span>
</td>
<td>
<template v-if="item.size">
- {{itemSize(item)}}
+ {{item.size}}
+ &middot;
+ {{layers(item)}}
</template>
<div v-else class="light">
\-
@@ -103,18 +142,20 @@
</div>
</td>
- <td>
- <button
- type="button"
- class="btn btn-remove"
- title="Remove tag"
- v-tooltip
- @click="deleteTag(item)">
- <i
- class="fa fa-trash cred"
- aria-hidden="true">
- </i>
- </button>
+ <td class="content">
+ <div class="controls hidden-xs pull-right">
+ <button
+ type="button"
+ class="btn btn-remove"
+ title="Remove tag"
+ v-tooltip
+ @click="handleDeleteRegistry(item)">
+ <i
+ class="fa fa-trash"
+ aria-hidden="true">
+ </i>
+ </button>
+ </div>
</td>
</tr>
</tbody>
@@ -123,9 +164,7 @@
v-else
class="nothing-here-block">
{{__("No tags in Container Registry for this container image.")}}
-
</div>
</div>
-
</div>
</template>
diff --git a/app/assets/javascripts/registry/constants.js b/app/assets/javascripts/registry/constants.js
new file mode 100644
index 00000000000..d3de6441dae
--- /dev/null
+++ b/app/assets/javascripts/registry/constants.js
@@ -0,0 +1,13 @@
+export const errorMessagesTypes = {
+ FETCH_REGISTRY: 'FETCH_REGISTRY',
+ FETCH_REPOS: 'FETCH_REPOS',
+ DELETE_REPO: 'DELETE_REPO',
+ DELETE_REGISTRY: 'DELETE_REGISTRY',
+};
+
+export const errorMessages = {
+ [errorMessagesTypes.FETCH_REGISTRY]: 'Something went wrong while fetching the registry list.',
+ [errorMessagesTypes.FETCH_REPOS]: 'Something went wrong while fetching the repositories.',
+ [errorMessagesTypes.DELETE_REPO]: 'Something went wrong while deleting the repository.',
+ [errorMessagesTypes.DELETE_REGISTRY]: 'Something went wrong while deleting registry.',
+};
diff --git a/app/assets/javascripts/registry/index.js b/app/assets/javascripts/registry/index.js
index e69de29bb2d..4f7895897b2 100644
--- a/app/assets/javascripts/registry/index.js
+++ b/app/assets/javascripts/registry/index.js
@@ -0,0 +1,25 @@
+import Vue from 'vue';
+import Translate from '../vue_shared/translate';
+import registryApp from './components/app.vue';
+
+// Vue.use(Translate);
+
+document.addEventListener('DOMContentLoaded', () => new Vue({
+ el: '#js-vue-registry-images',
+ components: {
+ registryApp,
+ },
+ data() {
+ const dataset = document.querySelector(this.$options.el).dataset;
+ return {
+ endpoint: dataset.endpoint,
+ };
+ },
+ render(createElement) {
+ return createElement('registry-app', {
+ props: {
+ endpoint: this.endpoint,
+ },
+ });
+ },
+}));
diff --git a/app/assets/javascripts/registry/stores/actions.js b/app/assets/javascripts/registry/stores/actions.js
index 6c0286e2be6..5dda16b8d9a 100644
--- a/app/assets/javascripts/registry/stores/actions.js
+++ b/app/assets/javascripts/registry/stores/actions.js
@@ -16,13 +16,13 @@ export const fetchRepos = ({ commit, state }) => {
};
export const fetchList = ({ commit }, list) => {
- commit(types.TOGGLE_IMAGE_LOADING, list);
+ commit(types.TOGGLE_REGISTRY_LIST_LOADING, list);
return Vue.http.get(list.path)
.then(res => res.json())
.then((response) => {
- commit(types.TOGGLE_IMAGE_LOADING, list);
- commit(types.SET_IMAGES_LIST, list, response);
+ commit(types.TOGGLE_REGISTRY_LIST_LOADING, list);
+ commit(types.SET_REGISTRY_LIST, list, response);
});
};
@@ -32,8 +32,11 @@ export const deleteRepo = ({ commit }, repo) => Vue.http.delete(repo.path)
commit(types.DELETE_REPO, repo);
});
-export const deleteImage = ({ commit }, image) => Vue.http.delete(image.path)
+export const deleteRegistry = ({ commit }, image) => Vue.http.delete(image.path)
.then(res => res.json())
.then(() => {
commit(types.DELETE_IMAGE, image);
});
+
+export const setMainEndpoint = ({ commit }, data) => commit(types.SET_MAIN_ENDPOINT, data);
+export const toggleIsLoading = ({ commit }) => commit(types.TOGGLE_MAIN_LOADING);
diff --git a/app/assets/javascripts/registry/stores/getters.js b/app/assets/javascripts/registry/stores/getters.js
new file mode 100644
index 00000000000..6c6ed0cd738
--- /dev/null
+++ b/app/assets/javascripts/registry/stores/getters.js
@@ -0,0 +1,2 @@
+export const isLoading = state => state.isLoading;
+export const repos = state => state.repos; \ No newline at end of file
diff --git a/app/assets/javascripts/registry/stores/index.js b/app/assets/javascripts/registry/stores/index.js
index 6cf9df57f08..78b67881210 100644
--- a/app/assets/javascripts/registry/stores/index.js
+++ b/app/assets/javascripts/registry/stores/index.js
@@ -1,6 +1,7 @@
import Vue from 'vue';
import Vuex from 'vuex';
-import actions from './actions';
+import * as actions from './actions';
+import * as getters from './getters';
import mutations from './mutations';
Vue.use(Vuex);
@@ -31,7 +32,8 @@ export default new Vuex.Store({
* }
*/
repos: [],
- actions,
- mutations,
},
+ actions,
+ getters,
+ mutations,
});
diff --git a/app/assets/javascripts/registry/stores/mutation_types.js b/app/assets/javascripts/registry/stores/mutation_types.js
index fb4e24e10e3..aece401a24a 100644
--- a/app/assets/javascripts/registry/stores/mutation_types.js
+++ b/app/assets/javascripts/registry/stores/mutation_types.js
@@ -1,9 +1,10 @@
+export const SET_MAIN_ENDPOINT = 'SET_MAIN_ENDPOINT';
export const FETCH_REPOS_LIST = 'FETCH_REPOS_LIST';
export const DELETE_REPO = 'DELETE_REPO';
export const SET_REPOS_LIST = 'SET_REPOS_LIST';
export const TOGGLE_MAIN_LOADING = 'TOGGLE_MAIN_LOADING';
export const FETCH_IMAGES_LIST = 'FETCH_IMAGES_LIST';
-export const SET_IMAGES_LIST = 'SET_IMAGES_LIST';
+export const SET_REGISTRY_LIST = 'SET_REGISTRY_LIST';
export const DELETE_IMAGE = 'DELETE_IMAGE';
-export const TOGGLE_IMAGE_LOADING = 'TOGGLE_MAIN_LOADING';
+export const TOGGLE_REGISTRY_LIST_LOADING = 'TOGGLE_REGISTRY_LIST_LOADING';
diff --git a/app/assets/javascripts/registry/stores/mutations.js b/app/assets/javascripts/registry/stores/mutations.js
index 5fa41fb5255..796548bffec 100644
--- a/app/assets/javascripts/registry/stores/mutations.js
+++ b/app/assets/javascripts/registry/stores/mutations.js
@@ -1,14 +1,22 @@
import * as types from './mutation_types';
export default {
+
+ [types.SET_MAIN_ENDPOINT](state, endpoint) {
+ Object.assign(state, { endpoint });
+ },
+
[types.SET_REPOS_LIST](state, list) {
Object.assign(state, {
repos: list.map(el => ({
- name: el.name,
- isLoading: false,
canDelete: !!el.destroy_path,
destroyPath: el.destroy_path,
+ isLoading: false,
list: [],
+ location: el.location,
+ name: el.name,
+ tagsPath: el.tags_path,
+ id: el.id,
})),
});
},
@@ -17,8 +25,29 @@ export default {
Object.assign(state, { isLoading: !state.isLoading });
},
- [types.SET_IMAGES_LIST](state, image, list) {
- const listToUpdate = state.repos.find(el => el.name === image.name);
+ [types.SET_REGISTRY_LIST](state, repo, list) {
+ // mock
+ list = [
+ {
+ name: 'centos6',
+ short_revision: '0b6091a66',
+ revision: '0b6091a665af68bbbbb36a3e088ec3cd6f35389deebf6d4617042d56722d76fb',
+ size: 706,
+ layers: 19,
+ created_at: 1505828744434,
+ },
+ {
+ name: 'centos7',
+ short_revision: 'b118ab5b0',
+ revision: 'b118ab5b0e90b7cb5127db31d5321ac14961d097516a8e0e72084b6cdc783b43',
+ size: 679,
+ layers: 19,
+ created_at: 1505828744434,
+ },
+ ];
+
+ const listToUpdate = state.repos.find(el => el.id === repo.id);
+
listToUpdate.list = list.map(element => ({
tag: element.name,
revision: element.revision,
@@ -31,8 +60,8 @@ export default {
}));
},
- [types.TOGGLE_IMAGE_LOADING](state, image) {
- const listToUpdate = state.repos.find(el => el.name === image.name);
+ [types.TOGGLE_REGISTRY_LIST_LOADING](state, list) {
+ const listToUpdate = state.repos.find(el => el.id === list.id);
listToUpdate.isLoading = !listToUpdate.isLoading;
},
};
diff --git a/app/assets/javascripts/vue_shared/components/clipboard_button.vue b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
index cb9ad4c7dee..fbf7233b13d 100644
--- a/app/assets/javascripts/vue_shared/components/clipboard_button.vue
+++ b/app/assets/javascripts/vue_shared/components/clipboard_button.vue
@@ -14,11 +14,11 @@
},
},
mounted() {
- return new Clipboard(this.$refs.btn, {
- text: () => {
- return this.text;
- },
- });
+ // return new Clipboard(this.$refs.btn, {
+ // text: () => {
+ // return this.text;
+ // },
+ // });
}
};
</script>
diff --git a/app/assets/stylesheets/pages/container_registry.scss b/app/assets/stylesheets/pages/container_registry.scss
index 3266714396e..089a693efe4 100644
--- a/app/assets/stylesheets/pages/container_registry.scss
+++ b/app/assets/stylesheets/pages/container_registry.scss
@@ -9,6 +9,10 @@
.container-image-head {
padding: 0 16px;
line-height: 4em;
+
+ &:hover {
+ text-decoration: underline;
+ }
}
.table.tags {
diff --git a/app/controllers/projects/registry/repositories_controller.rb b/app/controllers/projects/registry/repositories_controller.rb
index 71e7dc70a4d..89093e4172a 100644
--- a/app/controllers/projects/registry/repositories_controller.rb
+++ b/app/controllers/projects/registry/repositories_controller.rb
@@ -6,6 +6,37 @@ module Projects
def index
@images = project.container_repositories
+
+ respond_to do |format|
+ format.html
+ format.json do
+ # render json: @images
+ render json: [
+ {
+ name: 'gitlab-org/omnibus-gitlab/foo',
+ tags_path: 'foo',
+ destroy_path: 'bar',
+ location: 'foo',
+ id: '134',
+ destroy_path: 'bar'
+ },
+ {
+ name: 'gitlab-org/omnibus-gitlab',
+ tags_path: 'foo',
+ destroy_path: 'bar',
+ location: 'foo',
+ id: '123',
+ },
+ {
+ name: 'gitlab-org/omnibus-gitlab/bar',
+ tags_path: 'foo',
+ destroy_path: 'bar',
+ location: 'foo',
+ id: '973',
+ }
+ ]
+ end
+ end
end
def destroy
diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml
index 5661af01302..ab263091c1f 100644
--- a/app/views/projects/registry/repositories/index.html.haml
+++ b/app/views/projects/registry/repositories/index.html.haml
@@ -52,9 +52,15 @@
#{escape_once(@project.container_registry_url)}/optional-image-name:tag
#{escape_once(@project.container_registry_url)}/optional-name/optional-image-name:tag
- - if @images.blank?
- %p.settings-message.text-center.append-bottom-default
- No container images stored for this project. Add one by following the
- instructions above.
- - else
- = render partial: 'image', collection: @images
+ #js-vue-registry-images{ data: { endpoint: project_container_registry_index_path(@project, format: :json)}}
+
+ = page_specific_javascript_bundle_tag('common_vue')
+ = page_specific_javascript_bundle_tag('registry_list')
+
+
+ -# - if @images.blank?
+ -# %p.settings-message.text-center.append-bottom-default
+ -# No container images stored for this project. Add one by following the
+ -# instructions above.
+ -# - else
+ -# = render partial: 'image', collection: @images