summaryrefslogtreecommitdiff
path: root/app/assets
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-03-31 18:07:42 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-03-31 18:07:42 +0000
commit580622bdb3c762a8e89facd8a3946881ee480442 (patch)
tree3ac9d759da23f78f95f50684bd238a9f76839538 /app/assets
parentb211a4ea14d5e9ed9b0c248a4e8c5c1d85b542cb (diff)
downloadgitlab-ce-580622bdb3c762a8e89facd8a3946881ee480442.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/blob/pipeline_tour_success_modal.vue17
-rw-r--r--app/assets/javascripts/pages/groups/registry/repositories/index.js11
-rw-r--r--app/assets/javascripts/pages/projects/blob/show/index.js3
-rw-r--r--app/assets/javascripts/pages/projects/registry/repositories/index.js3
-rw-r--r--app/assets/javascripts/registry/list/components/app.vue153
-rw-r--r--app/assets/javascripts/registry/list/components/collapsible_container.vue155
-rw-r--r--app/assets/javascripts/registry/list/components/group_empty_state.vue46
-rw-r--r--app/assets/javascripts/registry/list/components/project_empty_state.vue133
-rw-r--r--app/assets/javascripts/registry/list/components/table_registry.vue289
-rw-r--r--app/assets/javascripts/registry/list/constants.js8
-rw-r--r--app/assets/javascripts/registry/list/index.js44
-rw-r--r--app/assets/javascripts/registry/list/stores/actions.js46
-rw-r--r--app/assets/javascripts/registry/list/stores/getters.js6
-rw-r--r--app/assets/javascripts/registry/list/stores/index.js15
-rw-r--r--app/assets/javascripts/registry/list/stores/mutation_types.js8
-rw-r--r--app/assets/javascripts/registry/list/stores/mutations.js57
-rw-r--r--app/assets/javascripts/registry/list/stores/state.js27
-rw-r--r--app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/participants/participants.vue2
-rw-r--r--app/assets/stylesheets/framework/buttons.scss1
-rw-r--r--app/assets/stylesheets/pages/issuable.scss13
21 files changed, 33 insertions, 1010 deletions
diff --git a/app/assets/javascripts/blob/pipeline_tour_success_modal.vue b/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
index 0739b4d5e39..179a515e5ca 100644
--- a/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
+++ b/app/assets/javascripts/blob/pipeline_tour_success_modal.vue
@@ -3,6 +3,9 @@ import { GlModal, GlSprintf, GlLink } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import Cookies from 'js-cookie';
import { glEmojiTag } from '~/emoji';
+import Tracking from '~/tracking';
+
+const trackingMixin = Tracking.mixin();
export default {
beginnerLink:
@@ -23,6 +26,7 @@ export default {
GlSprintf,
GlLink,
},
+ mixins: [trackingMixin],
props: {
goToPipelinesPath: {
type: String,
@@ -32,8 +36,21 @@ export default {
type: String,
required: true,
},
+ humanAccess: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ tracking: {
+ label: 'congratulate_first_pipeline',
+ property: this.humanAccess,
+ },
+ };
},
mounted() {
+ this.track();
this.disableModalFromRenderingAgain();
},
methods: {
diff --git a/app/assets/javascripts/pages/groups/registry/repositories/index.js b/app/assets/javascripts/pages/groups/registry/repositories/index.js
index 47fea2be189..cdafe838994 100644
--- a/app/assets/javascripts/pages/groups/registry/repositories/index.js
+++ b/app/assets/javascripts/pages/groups/registry/repositories/index.js
@@ -1,9 +1,10 @@
-import initRegistryImages from '~/registry/list/index';
import registryExplorer from '~/registry/explorer/index';
document.addEventListener('DOMContentLoaded', () => {
- initRegistryImages();
- const { attachMainComponent, attachBreadcrumb } = registryExplorer();
- attachBreadcrumb();
- attachMainComponent();
+ const explorer = registryExplorer();
+
+ if (explorer) {
+ explorer.attachBreadcrumb();
+ explorer.attachMainComponent();
+ }
});
diff --git a/app/assets/javascripts/pages/projects/blob/show/index.js b/app/assets/javascripts/pages/projects/blob/show/index.js
index 4d308d6b07a..9ff68a88f95 100644
--- a/app/assets/javascripts/pages/projects/blob/show/index.js
+++ b/app/assets/javascripts/pages/projects/blob/show/index.js
@@ -45,12 +45,13 @@ document.addEventListener('DOMContentLoaded', () => {
new Vue({
el: successPipelineEl,
render(createElement) {
- const { commitCookie, pipelinesPath: goToPipelinesPath } = this.$el.dataset;
+ const { commitCookie, goToPipelinesPath, humanAccess } = this.$el.dataset;
return createElement(PipelineTourSuccessModal, {
props: {
goToPipelinesPath,
commitCookie,
+ humanAccess,
},
});
},
diff --git a/app/assets/javascripts/pages/projects/registry/repositories/index.js b/app/assets/javascripts/pages/projects/registry/repositories/index.js
index 73469e287ed..cdafe838994 100644
--- a/app/assets/javascripts/pages/projects/registry/repositories/index.js
+++ b/app/assets/javascripts/pages/projects/registry/repositories/index.js
@@ -1,9 +1,6 @@
-import initRegistryImages from '~/registry/list/index';
import registryExplorer from '~/registry/explorer/index';
document.addEventListener('DOMContentLoaded', () => {
- initRegistryImages();
-
const explorer = registryExplorer();
if (explorer) {
diff --git a/app/assets/javascripts/registry/list/components/app.vue b/app/assets/javascripts/registry/list/components/app.vue
deleted file mode 100644
index c555c2b04d1..00000000000
--- a/app/assets/javascripts/registry/list/components/app.vue
+++ /dev/null
@@ -1,153 +0,0 @@
-<script>
-import { mapGetters, mapActions } from 'vuex';
-import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
-import store from '../stores';
-import CollapsibleContainer from './collapsible_container.vue';
-import ProjectEmptyState from './project_empty_state.vue';
-import GroupEmptyState from './group_empty_state.vue';
-import { s__, sprintf } from '~/locale';
-
-export default {
- name: 'RegistryListApp',
- components: {
- CollapsibleContainer,
- GlEmptyState,
- GlLoadingIcon,
- ProjectEmptyState,
- GroupEmptyState,
- },
- props: {
- characterError: {
- type: Boolean,
- required: false,
- default: false,
- },
- containersErrorImage: {
- type: String,
- required: true,
- },
- endpoint: {
- type: String,
- required: true,
- },
- helpPagePath: {
- type: String,
- required: true,
- },
- noContainersImage: {
- type: String,
- required: true,
- },
- personalAccessTokensHelpLink: {
- type: String,
- required: false,
- default: null,
- },
- registryHostUrlWithPort: {
- type: String,
- required: false,
- default: null,
- },
- repositoryUrl: {
- type: String,
- required: true,
- },
- isGroupPage: {
- type: Boolean,
- default: false,
- required: false,
- },
- twoFactorAuthHelpLink: {
- type: String,
- required: false,
- default: null,
- },
- },
- store,
- computed: {
- ...mapGetters(['isLoading', 'repos']),
- dockerConnectionErrorText() {
- return sprintf(
- s__(`ContainerRegistry|We are having trouble connecting to Docker, which could be due to an
- issue with your project name or path.
- %{docLinkStart}More Information%{docLinkEnd}`),
- {
- docLinkStart: `<a href="${this.helpPagePath}#docker-connection-error" target="_blank">`,
- docLinkEnd: '</a>',
- },
- false,
- );
- },
- introText() {
- return sprintf(
- s__(`ContainerRegistry|With the Docker Container Registry integrated into GitLab, every
- project can have its own space to store its Docker images.
- %{docLinkStart}More Information%{docLinkEnd}`),
- {
- docLinkStart: `<a href="${this.helpPagePath}" target="_blank">`,
- docLinkEnd: '</a>',
- },
- false,
- );
- },
- noContainerImagesText() {
- return sprintf(
- s__(`ContainerRegistry|With the Container Registry, every project can have its own space to
- store its Docker images. %{docLinkStart}More Information%{docLinkEnd}`),
- {
- docLinkStart: `<a href="${this.helpPagePath}" target="_blank">`,
- docLinkEnd: '</a>',
- },
- false,
- );
- },
- },
- created() {
- this.setMainEndpoint(this.endpoint);
- this.setIsDeleteDisabled(this.isGroupPage);
- },
- mounted() {
- if (!this.characterError) {
- this.fetchRepos();
- }
- },
- methods: {
- ...mapActions(['setMainEndpoint', 'fetchRepos', 'setIsDeleteDisabled']),
- },
-};
-</script>
-<template>
- <div>
- <gl-empty-state
- v-if="characterError"
- :title="s__('ContainerRegistry|Docker connection error')"
- :svg-path="containersErrorImage"
- >
- <template #description>
- <p class="js-character-error-text" v-html="dockerConnectionErrorText"></p>
- </template>
- </gl-empty-state>
-
- <gl-loading-icon v-else-if="isLoading" size="md" class="prepend-top-16" />
-
- <div v-else-if="!isLoading && repos.length">
- <h4>{{ s__('ContainerRegistry|Container Registry') }}</h4>
- <p v-html="introText"></p>
- <collapsible-container v-for="item in repos" :key="item.id" :repo="item" />
- </div>
- <project-empty-state
- v-else-if="!isGroupPage"
- :no-containers-image="noContainersImage"
- :help-page-path="helpPagePath"
- :repository-url="repositoryUrl"
- :two-factor-auth-help-link="twoFactorAuthHelpLink"
- :personal-access-tokens-help-link="personalAccessTokensHelpLink"
- :registry-host-url-with-port="registryHostUrlWithPort"
- />
- <group-empty-state
- v-else-if="isGroupPage"
- :no-containers-image="noContainersImage"
- :help-page-path="helpPagePath"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/registry/list/components/collapsible_container.vue b/app/assets/javascripts/registry/list/components/collapsible_container.vue
deleted file mode 100644
index 9786a1a3f75..00000000000
--- a/app/assets/javascripts/registry/list/components/collapsible_container.vue
+++ /dev/null
@@ -1,155 +0,0 @@
-<script>
-import { mapActions, mapGetters } from 'vuex';
-import {
- GlLoadingIcon,
- GlButton,
- GlTooltipDirective,
- GlModal,
- GlModalDirective,
- GlEmptyState,
-} from '@gitlab/ui';
-import createFlash from '~/flash';
-import Tracking from '~/tracking';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import Icon from '~/vue_shared/components/icon.vue';
-import TableRegistry from './table_registry.vue';
-import { DELETE_REPO_ERROR_MESSAGE } from '../constants';
-import { __, sprintf } from '~/locale';
-
-export default {
- name: 'CollapsibeContainerRegisty',
- components: {
- ClipboardButton,
- TableRegistry,
- GlLoadingIcon,
- GlButton,
- Icon,
- GlModal,
- GlEmptyState,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- GlModal: GlModalDirective,
- },
- mixins: [Tracking.mixin()],
- props: {
- repo: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- isOpen: false,
- modalId: `confirm-repo-deletion-modal-${this.repo.id}`,
- tracking: {
- label: 'registry_repository_delete',
- },
- };
- },
- computed: {
- ...mapGetters(['isDeleteDisabled']),
- iconName() {
- return this.isOpen ? 'angle-up' : 'angle-right';
- },
- canDeleteRepo() {
- return this.repo.canDelete && !this.isDeleteDisabled;
- },
- deleteImageConfirmationMessage() {
- return sprintf(__('Image %{imageName} was scheduled for deletion from the registry.'), {
- imageName: this.repo.name,
- });
- },
- },
- methods: {
- ...mapActions(['fetchRepos', 'fetchList', 'deleteItem']),
- toggleRepo() {
- this.isOpen = !this.isOpen;
-
- if (this.isOpen) {
- this.fetchList({ repo: this.repo });
- }
- },
- handleDeleteRepository() {
- this.track('confirm_delete');
- return this.deleteItem(this.repo)
- .then(() => {
- createFlash(this.deleteImageConfirmationMessage, 'notice');
- this.fetchRepos();
- })
- .catch(() => createFlash(DELETE_REPO_ERROR_MESSAGE));
- },
- },
-};
-</script>
-
-<template>
- <div class="container-image">
- <div class="container-image-head">
- <gl-button class="js-toggle-repo btn-link align-baseline" @click="toggleRepo">
- <icon :name="iconName" />
- {{ repo.name }}
- </gl-button>
-
- <clipboard-button
- v-if="repo.location"
- :text="repo.location"
- :title="repo.location"
- css-class="btn-default btn-transparent btn-clipboard"
- />
-
- <div class="controls d-none d-sm-block float-right">
- <gl-button
- v-if="canDeleteRepo"
- v-gl-tooltip
- v-gl-modal="modalId"
- :title="s__('ContainerRegistry|Remove repository')"
- :aria-label="s__('ContainerRegistry|Remove repository')"
- class="js-remove-repo btn-inverted"
- variant="danger"
- @click="track('click_button')"
- >
- <icon name="remove" />
- </gl-button>
- </div>
- </div>
-
- <gl-loading-icon v-if="repo.isLoading" size="md" class="append-bottom-20" />
-
- <div v-else-if="!repo.isLoading && isOpen" class="container-image-tags">
- <table-registry v-if="repo.list.length" :repo="repo" :can-delete-repo="canDeleteRepo" />
- <gl-empty-state
- v-else
- :title="s__('ContainerRegistry|This image has no active tags')"
- :description="
- s__(
- `ContainerRegistry|The last tag related to this image was recently removed.
- This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process.
- If you have any questions, contact your administrator.`,
- )
- "
- class="mx-auto my-0"
- />
- </div>
- <gl-modal
- ref="deleteModal"
- :modal-id="modalId"
- ok-variant="danger"
- @ok="handleDeleteRepository"
- @cancel="track('cancel_delete')"
- >
- <template v-slot:modal-title>{{ s__('ContainerRegistry|Remove repository') }}</template>
- <p
- v-html="
- sprintf(
- s__(
- 'ContainerRegistry|You are about to remove repository <b>%{title}</b>. Once you confirm, this repository will be permanently deleted.',
- ),
- { title: repo.name },
- )
- "
- ></p>
- <template v-slot:modal-ok>{{ __('Remove') }}</template>
- </gl-modal>
- </div>
-</template>
diff --git a/app/assets/javascripts/registry/list/components/group_empty_state.vue b/app/assets/javascripts/registry/list/components/group_empty_state.vue
deleted file mode 100644
index 7885fd2146d..00000000000
--- a/app/assets/javascripts/registry/list/components/group_empty_state.vue
+++ /dev/null
@@ -1,46 +0,0 @@
-<script>
-import { GlEmptyState } from '@gitlab/ui';
-import { s__, sprintf } from '~/locale';
-
-export default {
- name: 'GroupEmptyState',
- components: {
- GlEmptyState,
- },
- props: {
- noContainersImage: {
- type: String,
- required: true,
- },
- helpPagePath: {
- type: String,
- required: true,
- },
- },
- computed: {
- noContainerImagesText() {
- return sprintf(
- s__(
- `ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. Push at least one Docker image in one of this group's projects in order to show up here. %{docLinkStart}More Information%{docLinkEnd}`,
- ),
- {
- docLinkStart: `<a href="${this.helpPagePath}" target="_blank">`,
- docLinkEnd: '</a>',
- },
- false,
- );
- },
- },
-};
-</script>
-<template>
- <gl-empty-state
- :title="s__('ContainerRegistry|There are no container images available in this group')"
- :svg-path="noContainersImage"
- class="container-message"
- >
- <template #description>
- <p class="js-no-container-images-text" v-html="noContainerImagesText"></p>
- </template>
- </gl-empty-state>
-</template>
diff --git a/app/assets/javascripts/registry/list/components/project_empty_state.vue b/app/assets/javascripts/registry/list/components/project_empty_state.vue
deleted file mode 100644
index 900498ed03d..00000000000
--- a/app/assets/javascripts/registry/list/components/project_empty_state.vue
+++ /dev/null
@@ -1,133 +0,0 @@
-<script>
-import { GlEmptyState } from '@gitlab/ui';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import { s__, sprintf } from '~/locale';
-
-export default {
- name: 'ProjectEmptyState',
- components: {
- ClipboardButton,
- GlEmptyState,
- },
- props: {
- noContainersImage: {
- type: String,
- required: true,
- },
- repositoryUrl: {
- type: String,
- required: true,
- },
- helpPagePath: {
- type: String,
- required: true,
- },
- twoFactorAuthHelpLink: {
- type: String,
- required: true,
- },
- personalAccessTokensHelpLink: {
- type: String,
- required: true,
- },
- registryHostUrlWithPort: {
- type: String,
- required: true,
- },
- },
- computed: {
- dockerBuildCommand() {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- return `docker build -t ${this.repositoryUrl} .`;
- },
- dockerPushCommand() {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- return `docker push ${this.repositoryUrl}`;
- },
- dockerLoginCommand() {
- // eslint-disable-next-line @gitlab/require-i18n-strings
- return `docker login ${this.registryHostUrlWithPort}`;
- },
- noContainerImagesText() {
- return sprintf(
- s__(`ContainerRegistry|With the Container Registry, every project can have its own space to
- store its Docker images. %{docLinkStart}More Information%{docLinkEnd}`),
- {
- docLinkStart: `<a href="${this.helpPagePath}" target="_blank">`,
- docLinkEnd: '</a>',
- },
- false,
- );
- },
- notLoggedInToRegistryText() {
- return sprintf(
- s__(`ContainerRegistry|If you are not already logged in, you need to authenticate to
- the Container Registry by using your GitLab username and password. If you have
- %{twofaDocLinkStart}Two-Factor Authentication%{twofaDocLinkEnd} enabled, use a
- %{personalAccessTokensDocLinkStart}Personal Access Token%{personalAccessTokensDocLinkEnd}
- instead of a password.`),
- {
- twofaDocLinkStart: `<a href="${this.twoFactorAuthHelpLink}" target="_blank">`,
- twofaDocLinkEnd: '</a>',
- personalAccessTokensDocLinkStart: `<a href="${this.personalAccessTokensHelpLink}" target="_blank">`,
- personalAccessTokensDocLinkEnd: '</a>',
- },
- false,
- );
- },
- },
-};
-</script>
-<template>
- <gl-empty-state
- :title="s__('ContainerRegistry|There are no container images stored for this project')"
- :svg-path="noContainersImage"
- class="container-message"
- >
- <template #description>
- <p class="js-no-container-images-text" v-html="noContainerImagesText"></p>
- <h5>{{ s__('ContainerRegistry|Quick Start') }}</h5>
- <p class="js-not-logged-in-to-registry-text" v-html="notLoggedInToRegistryText"></p>
- <div class="input-group append-bottom-10">
- <input :value="dockerLoginCommand" type="text" class="form-control monospace" readonly />
- <span class="input-group-append">
- <clipboard-button
- :text="dockerLoginCommand"
- :title="s__('ContainerRegistry|Copy login command')"
- class="input-group-text"
- />
- </span>
- </div>
- <p></p>
- <p>
- {{
- s__(
- 'ContainerRegistry|You can add an image to this registry with the following commands:',
- )
- }}
- </p>
-
- <div class="input-group append-bottom-10">
- <input :value="dockerBuildCommand" type="text" class="form-control monospace" readonly />
- <span class="input-group-append">
- <clipboard-button
- :text="dockerBuildCommand"
- :title="s__('ContainerRegistry|Copy build command')"
- class="input-group-text"
- />
- </span>
- </div>
-
- <div class="input-group">
- <input :value="dockerPushCommand" type="text" class="form-control monospace" readonly />
- <span class="input-group-append">
- <clipboard-button
- :text="dockerPushCommand"
- :title="s__('ContainerRegistry|Copy push command')"
- class="input-group-text"
- />
- </span>
- </div>
- </template>
- </gl-empty-state>
-</template>
diff --git a/app/assets/javascripts/registry/list/components/table_registry.vue b/app/assets/javascripts/registry/list/components/table_registry.vue
deleted file mode 100644
index 4e14db7f578..00000000000
--- a/app/assets/javascripts/registry/list/components/table_registry.vue
+++ /dev/null
@@ -1,289 +0,0 @@
-<script>
-import { mapActions, mapGetters } from 'vuex';
-import { GlButton, GlFormCheckbox, GlTooltipDirective, GlModal } from '@gitlab/ui';
-import Tracking from '~/tracking';
-import { n__, s__, sprintf } from '~/locale';
-import createFlash from '~/flash';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
-import Icon from '~/vue_shared/components/icon.vue';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { FETCH_REGISTRY_ERROR_MESSAGE, DELETE_REGISTRY_ERROR_MESSAGE } from '../constants';
-
-export default {
- components: {
- ClipboardButton,
- TablePagination,
- GlFormCheckbox,
- GlButton,
- Icon,
- GlModal,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [timeagoMixin, Tracking.mixin()],
- props: {
- repo: {
- type: Object,
- required: true,
- },
- canDeleteRepo: {
- type: Boolean,
- default: false,
- required: false,
- },
- },
- data() {
- return {
- selectedItems: [],
- itemsToBeDeleted: [],
- modalId: `confirm-image-deletion-modal-${this.repo.id}`,
- selectAllChecked: false,
- modalDescription: '',
- };
- },
- computed: {
- ...mapGetters(['isDeleteDisabled']),
- bulkDeletePath() {
- return this.repo.tagsPath ? this.repo.tagsPath.replace('?format=json', '/bulk_destroy') : '';
- },
- shouldRenderPagination() {
- return this.repo.pagination.total > this.repo.pagination.perPage;
- },
- modalAction() {
- return n__(
- 'ContainerRegistry|Remove tag',
- 'ContainerRegistry|Remove tags',
- this.itemsToBeDeleted.length === 0 ? 1 : this.itemsToBeDeleted.length,
- );
- },
- isMultiDelete() {
- return this.itemsToBeDeleted.length > 1;
- },
- tracking() {
- return {
- property: this.repo.name,
- label: this.isMultiDelete ? 'bulk_registry_tag_delete' : 'registry_tag_delete',
- };
- },
- },
- methods: {
- ...mapActions(['fetchList', 'deleteItem', 'multiDeleteItems']),
- setModalDescription(itemIndex = -1) {
- if (itemIndex === -1) {
- this.modalDescription = sprintf(
- s__(`ContainerRegistry|You are about to remove <b>%{count}</b> tags. Are you sure?`),
- { count: this.itemsToBeDeleted.length },
- );
- } else {
- const { tag } = this.repo.list[itemIndex];
-
- this.modalDescription = sprintf(
- s__(`ContainerRegistry|You are about to remove <b>%{title}</b>. Are you sure?`),
- { title: `${this.repo.name}:${tag}` },
- );
- }
- },
- layers(item) {
- return item.layers ? n__('%d layer', '%d layers', item.layers) : '';
- },
- formatSize(size) {
- return numberToHumanSize(size);
- },
- deleteSingleItem(index) {
- this.setModalDescription(index);
- this.itemsToBeDeleted = [index];
- this.track('click_button');
- this.$refs.deleteModal.show();
- },
- deleteMultipleItems() {
- this.itemsToBeDeleted = [...this.selectedItems];
- if (this.selectedItems.length === 1) {
- this.setModalDescription(this.itemsToBeDeleted[0]);
- } else if (this.selectedItems.length > 1) {
- this.setModalDescription();
- }
- this.track('click_button');
- this.$refs.deleteModal.show();
- },
- handleSingleDelete(itemToDelete) {
- this.itemsToBeDeleted = [];
- this.deleteItem(itemToDelete)
- .then(() => this.fetchList({ repo: this.repo }))
- .catch(() => createFlash(DELETE_REGISTRY_ERROR_MESSAGE));
- },
- handleMultipleDelete() {
- const { itemsToBeDeleted } = this;
- this.itemsToBeDeleted = [];
- this.selectedItems = [];
-
- if (this.bulkDeletePath) {
- this.multiDeleteItems({
- path: this.bulkDeletePath,
- items: itemsToBeDeleted.map(x => this.repo.list[x].tag),
- })
- .then(() => this.fetchList({ repo: this.repo }))
- .catch(() => createFlash(DELETE_REGISTRY_ERROR_MESSAGE));
- } else {
- createFlash(DELETE_REGISTRY_ERROR_MESSAGE);
- }
- },
- onPageChange(pageNumber) {
- this.fetchList({ repo: this.repo, page: pageNumber }).catch(() =>
- createFlash(FETCH_REGISTRY_ERROR_MESSAGE),
- );
- },
- onSelectAllChange() {
- if (this.selectAllChecked) {
- this.deselectAll();
- } else {
- this.selectAll();
- }
- },
- selectAll() {
- this.selectedItems = this.repo.list.map((x, index) => index);
- this.selectAllChecked = true;
- },
- deselectAll() {
- this.selectedItems = [];
- this.selectAllChecked = false;
- },
- updateselectedItems(index) {
- const delIndex = this.selectedItems.findIndex(x => x === index);
-
- if (delIndex > -1) {
- this.selectedItems.splice(delIndex, 1);
- this.selectAllChecked = false;
- } else {
- this.selectedItems.push(index);
-
- if (this.selectedItems.length === this.repo.list.length) {
- this.selectAllChecked = true;
- }
- }
- },
- canDeleteRow(item) {
- return item && item.canDelete && !this.isDeleteDisabled;
- },
- onDeletionConfirmed() {
- this.track('confirm_delete');
- if (this.isMultiDelete) {
- this.handleMultipleDelete();
- } else {
- const index = this.itemsToBeDeleted[0];
- this.handleSingleDelete(this.repo.list[index]);
- }
- },
- },
-};
-</script>
-<template>
- <div>
- <table class="table tags">
- <thead>
- <tr>
- <th>
- <gl-form-checkbox
- v-if="canDeleteRepo"
- class="js-select-all-checkbox"
- :checked="selectAllChecked"
- @change="onSelectAllChange"
- />
- </th>
- <th>{{ s__('ContainerRegistry|Tag') }}</th>
- <th ref="imageId">{{ s__('ContainerRegistry|Image ID') }}</th>
- <th>{{ s__('ContainerRegistry|Size') }}</th>
- <th>{{ s__('ContainerRegistry|Last Updated') }}</th>
- <th>
- <gl-button
- v-if="canDeleteRepo"
- ref="bulkDeleteButton"
- v-gl-tooltip
- :disabled="!selectedItems || selectedItems.length === 0"
- class="float-right"
- variant="danger"
- :title="s__('ContainerRegistry|Remove selected tags')"
- :aria-label="s__('ContainerRegistry|Remove selected tags')"
- @click="deleteMultipleItems()"
- >
- <icon name="remove" />
- </gl-button>
- </th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="(item, index) in repo.list" :key="item.tag" class="registry-image-row">
- <td class="check">
- <gl-form-checkbox
- v-if="canDeleteRow(item)"
- class="js-select-checkbox"
- :checked="selectedItems && selectedItems.includes(index)"
- @change="updateselectedItems(index)"
- />
- </td>
- <td class="monospace">
- {{ item.tag }}
- <clipboard-button
- v-if="item.location"
- :title="item.location"
- :text="item.location"
- css-class="btn-default btn-transparent btn-clipboard"
- />
- </td>
- <td>
- <span v-gl-tooltip.bottom class="monospace" :title="item.revision">{{
- item.shortRevision
- }}</span>
- </td>
- <td>
- {{ formatSize(item.size) }}
- <template v-if="item.size && item.layers"
- >&middot;</template
- >
- {{ layers(item) }}
- </td>
-
- <td>
- <span v-gl-tooltip.bottom :title="tooltipTitle(item.createdAt)">{{
- timeFormatted(item.createdAt)
- }}</span>
- </td>
-
- <td class="content action-buttons">
- <gl-button
- v-if="canDeleteRow(item)"
- :title="s__('ContainerRegistry|Remove tag')"
- :aria-label="s__('ContainerRegistry|Remove tag')"
- variant="danger"
- class="js-delete-registry-row float-right btn-inverted btn-border-color btn-icon"
- @click="deleteSingleItem(index)"
- >
- <icon name="remove" />
- </gl-button>
- </td>
- </tr>
- </tbody>
- </table>
-
- <table-pagination
- v-if="shouldRenderPagination"
- :change="onPageChange"
- :page-info="repo.pagination"
- class="js-registry-pagination"
- />
-
- <gl-modal
- ref="deleteModal"
- :modal-id="modalId"
- ok-variant="danger"
- @ok="onDeletionConfirmed"
- @cancel="track('cancel_delete')"
- >
- <template v-slot:modal-title>{{ modalAction }}</template>
- <template v-slot:modal-ok>{{ modalAction }}</template>
- <p v-html="modalDescription"></p>
- </gl-modal>
- </div>
-</template>
diff --git a/app/assets/javascripts/registry/list/constants.js b/app/assets/javascripts/registry/list/constants.js
deleted file mode 100644
index e55ea9cc9d9..00000000000
--- a/app/assets/javascripts/registry/list/constants.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import { __ } from '~/locale';
-
-export const FETCH_REGISTRY_ERROR_MESSAGE = __(
- 'Something went wrong while fetching the registry list.',
-);
-export const FETCH_REPOS_ERROR_MESSAGE = __('Something went wrong while fetching the projects.');
-export const DELETE_REPO_ERROR_MESSAGE = __('Something went wrong on our end.');
-export const DELETE_REGISTRY_ERROR_MESSAGE = __('Something went wrong on our end.');
diff --git a/app/assets/javascripts/registry/list/index.js b/app/assets/javascripts/registry/list/index.js
deleted file mode 100644
index e8e54fda169..00000000000
--- a/app/assets/javascripts/registry/list/index.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import Vue from 'vue';
-import registryApp from './components/app.vue';
-import Translate from '~/vue_shared/translate';
-
-Vue.use(Translate);
-
-export default () => {
- const el = document.getElementById('js-vue-registry-images');
-
- if (!el) {
- return null;
- }
-
- return new Vue({
- el,
- components: {
- registryApp,
- },
- data() {
- const { dataset } = el;
- return {
- registryData: {
- endpoint: dataset.endpoint,
- characterError: Boolean(dataset.characterError),
- helpPagePath: dataset.helpPagePath,
- noContainersImage: dataset.noContainersImage,
- containersErrorImage: dataset.containersErrorImage,
- repositoryUrl: dataset.repositoryUrl,
- isGroupPage: dataset.isGroupPage,
- personalAccessTokensHelpLink: dataset.personalAccessTokensHelpLink,
- registryHostUrlWithPort: dataset.registryHostUrlWithPort,
- twoFactorAuthHelpLink: dataset.twoFactorAuthHelpLink,
- },
- };
- },
- render(createElement) {
- return createElement('registry-app', {
- props: {
- ...this.registryData,
- },
- });
- },
- });
-};
diff --git a/app/assets/javascripts/registry/list/stores/actions.js b/app/assets/javascripts/registry/list/stores/actions.js
deleted file mode 100644
index 6afba618486..00000000000
--- a/app/assets/javascripts/registry/list/stores/actions.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import axios from '~/lib/utils/axios_utils';
-import createFlash from '~/flash';
-import * as types from './mutation_types';
-import { FETCH_REPOS_ERROR_MESSAGE, FETCH_REGISTRY_ERROR_MESSAGE } from '../constants';
-
-export const fetchRepos = ({ commit, state }) => {
- commit(types.TOGGLE_MAIN_LOADING);
-
- return axios
- .get(state.endpoint)
- .then(({ data }) => {
- commit(types.TOGGLE_MAIN_LOADING);
- commit(types.SET_REPOS_LIST, data);
- })
- .catch(() => {
- commit(types.TOGGLE_MAIN_LOADING);
- createFlash(FETCH_REPOS_ERROR_MESSAGE);
- });
-};
-
-export const fetchList = ({ commit }, { repo, page }) => {
- commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo);
- return axios
- .get(repo.tagsPath, { params: { page } })
- .then(response => {
- const { headers, data } = response;
-
- commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo);
- commit(types.SET_REGISTRY_LIST, { repo, resp: data, headers });
- })
- .catch(() => {
- commit(types.TOGGLE_REGISTRY_LIST_LOADING, repo);
- createFlash(FETCH_REGISTRY_ERROR_MESSAGE);
- });
-};
-
-export const deleteItem = (_, item) => axios.delete(item.destroyPath);
-export const multiDeleteItems = (_, { path, items }) =>
- axios.delete(path, { params: { ids: items } });
-
-export const setMainEndpoint = ({ commit }, data) => commit(types.SET_MAIN_ENDPOINT, data);
-export const setIsDeleteDisabled = ({ commit }, data) => commit(types.SET_IS_DELETE_DISABLED, data);
-export const toggleLoading = ({ commit }) => commit(types.TOGGLE_MAIN_LOADING);
-
-// prevent babel-plugin-rewire from generating an invalid default during karma tests
-export default () => {};
diff --git a/app/assets/javascripts/registry/list/stores/getters.js b/app/assets/javascripts/registry/list/stores/getters.js
deleted file mode 100644
index ac90bde1b2a..00000000000
--- a/app/assets/javascripts/registry/list/stores/getters.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export const isLoading = state => state.isLoading;
-export const repos = state => state.repos;
-export const isDeleteDisabled = state => state.isDeleteDisabled;
-
-// prevent babel-plugin-rewire from generating an invalid default during karma tests
-export default () => {};
diff --git a/app/assets/javascripts/registry/list/stores/index.js b/app/assets/javascripts/registry/list/stores/index.js
deleted file mode 100644
index 1bb06bd6e81..00000000000
--- a/app/assets/javascripts/registry/list/stores/index.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import Vue from 'vue';
-import Vuex from 'vuex';
-import * as actions from './actions';
-import * as getters from './getters';
-import mutations from './mutations';
-import createState from './state';
-
-Vue.use(Vuex);
-
-export default new Vuex.Store({
- state: createState(),
- actions,
- getters,
- mutations,
-});
diff --git a/app/assets/javascripts/registry/list/stores/mutation_types.js b/app/assets/javascripts/registry/list/stores/mutation_types.js
deleted file mode 100644
index 6740bfede1a..00000000000
--- a/app/assets/javascripts/registry/list/stores/mutation_types.js
+++ /dev/null
@@ -1,8 +0,0 @@
-export const SET_MAIN_ENDPOINT = 'SET_MAIN_ENDPOINT';
-export const SET_IS_DELETE_DISABLED = 'SET_IS_DELETE_DISABLED';
-
-export const SET_REPOS_LIST = 'SET_REPOS_LIST';
-export const TOGGLE_MAIN_LOADING = 'TOGGLE_MAIN_LOADING';
-
-export const SET_REGISTRY_LIST = 'SET_REGISTRY_LIST';
-export const TOGGLE_REGISTRY_LIST_LOADING = 'TOGGLE_REGISTRY_LIST_LOADING';
diff --git a/app/assets/javascripts/registry/list/stores/mutations.js b/app/assets/javascripts/registry/list/stores/mutations.js
deleted file mode 100644
index 419de848883..00000000000
--- a/app/assets/javascripts/registry/list/stores/mutations.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import * as types from './mutation_types';
-import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
-
-export default {
- [types.SET_MAIN_ENDPOINT](state, endpoint) {
- state.endpoint = endpoint;
- },
-
- [types.SET_IS_DELETE_DISABLED](state, isDeleteDisabled) {
- state.isDeleteDisabled = isDeleteDisabled;
- },
-
- [types.SET_REPOS_LIST](state, list) {
- state.repos = list.map(el => ({
- canDelete: Boolean(el.destroy_path),
- destroyPath: el.destroy_path,
- id: el.id,
- isLoading: false,
- list: [],
- location: el.location,
- name: el.path,
- tagsPath: el.tags_path,
- projectId: el.project_id,
- }));
- },
-
- [types.TOGGLE_MAIN_LOADING](state) {
- state.isLoading = !state.isLoading;
- },
-
- [types.SET_REGISTRY_LIST](state, { repo, resp, headers }) {
- const listToUpdate = state.repos.find(el => el.id === repo.id);
-
- const normalizedHeaders = normalizeHeaders(headers);
- const pagination = parseIntPagination(normalizedHeaders);
-
- listToUpdate.pagination = pagination;
-
- listToUpdate.list = resp.map(element => ({
- tag: element.name,
- revision: element.revision,
- shortRevision: element.short_revision,
- size: element.total_size,
- layers: element.layers,
- location: element.location,
- createdAt: element.created_at,
- destroyPath: element.destroy_path,
- canDelete: Boolean(element.destroy_path),
- }));
- },
-
- [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/registry/list/stores/state.js b/app/assets/javascripts/registry/list/stores/state.js
deleted file mode 100644
index 724c64b4994..00000000000
--- a/app/assets/javascripts/registry/list/stores/state.js
+++ /dev/null
@@ -1,27 +0,0 @@
-export default () => ({
- isLoading: false,
- endpoint: '', // initial endpoint to fetch the repos list
- isDeleteDisabled: false, // controls the delete buttons in the registry
- /**
- * Each object in `repos` has the following strucure:
- * {
- * name: String,
- * isLoading: Boolean,
- * tagsPath: String // endpoint to request the list
- * destroyPath: String // endpoit to delete the repo
- * list: Array // List of the registry images
- * }
- *
- * Each registry image inside `list` has the following structure:
- * {
- * tag: String,
- * revision: String
- * shortRevision: String
- * size: Number
- * layers: Number
- * createdAt: String
- * destroyPath: String // endpoit to delete each image
- * }
- */
- repos: [],
-});
diff --git a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
index 012a4f4ad89..728f655d33d 100644
--- a/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
+++ b/app/assets/javascripts/sidebar/components/lock/lock_issue_sidebar.vue
@@ -106,17 +106,17 @@ export default {
<div class="title hide-collapsed">
{{ sprintf(__('Lock %{issuableDisplayName}'), { issuableDisplayName: issuableDisplayName }) }}
- <button
+ <a
v-if="isEditable"
class="float-right lock-edit"
- type="button"
+ href="#"
data-track-event="click_edit_button"
data-track-label="right_sidebar"
data-track-property="lock_issue"
@click.prevent="toggleForm"
>
{{ __('Edit') }}
- </button>
+ </a>
</div>
<div class="value sidebar-item-value hide-collapsed">
diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue
index f2ef7a2268e..db2e51c3aca 100644
--- a/app/assets/javascripts/sidebar/components/participants/participants.vue
+++ b/app/assets/javascripts/sidebar/components/participants/participants.vue
@@ -127,7 +127,7 @@ export default {
<div v-if="hasMoreParticipants" class="participants-more hide-collapsed">
<button
type="button"
- class="btn-transparent btn-blank js-toggle-participants-button"
+ class="btn-transparent btn-link js-toggle-participants-button"
@click="toggleMoreParticipants"
>
{{ toggleLabel }}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 38cef3de777..6257ee3ae8e 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -447,6 +447,7 @@
font-weight: normal;
border-radius: 0;
border-color: transparent;
+ border-width: 0;
&:hover,
&:active,
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index d61fbae81f2..c48f4b0622e 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -187,7 +187,6 @@
.btn-link {
color: inherit;
- outline: none;
}
.issuable-header-text {
@@ -261,15 +260,10 @@
color: rgba($gray-normal, 0.2);
}
- .lock-edit, // uses same style, different js behaviour
+ .confidential-edit,
+ .lock-edit,
.edit-link {
- @extend .btn-blank;
- color: $gl-text-color;
-
- &:hover {
- text-decoration: underline;
- color: $blue-800;
- }
+ @extend .btn-link;
}
}
@@ -689,7 +683,6 @@
}
.btn-link {
- outline: none;
padding: 0;
}