Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
daf5e72855
commit
e5de3582ae
|
|
@ -181,6 +181,7 @@ class GfmAutoComplete {
|
|||
skipSpecialCharacterTest: true,
|
||||
skipMarkdownCharacterTest: true,
|
||||
data: GfmAutoComplete.defaultLoadingData,
|
||||
maxLen: 100,
|
||||
displayTpl(value) {
|
||||
const cssClasses = [];
|
||||
|
||||
|
|
@ -297,6 +298,7 @@ class GfmAutoComplete {
|
|||
at: '/submit_review ',
|
||||
alias: 'submit_review',
|
||||
data: Object.keys(REVIEW_STATES),
|
||||
maxLen: 100,
|
||||
displayTpl({ name }) {
|
||||
const reviewState = REVIEW_STATES[name];
|
||||
|
||||
|
|
@ -315,6 +317,7 @@ class GfmAutoComplete {
|
|||
insertTpl: GfmAutoComplete.Emoji.insertTemplateFunction,
|
||||
skipSpecialCharacterTest: true,
|
||||
data: GfmAutoComplete.defaultLoadingData,
|
||||
maxLen: 100,
|
||||
callbacks: {
|
||||
...this.getDefaultCallbacks(),
|
||||
matcher(flag, subtext) {
|
||||
|
|
@ -373,6 +376,7 @@ class GfmAutoComplete {
|
|||
$input.atwho({
|
||||
at: '@',
|
||||
alias: USERS_ALIAS,
|
||||
maxLen: 100,
|
||||
displayTpl(value) {
|
||||
let tmpl = GfmAutoComplete.Loading.template;
|
||||
const { avatarTag, username, title, icon, availability } = value;
|
||||
|
|
@ -478,6 +482,7 @@ class GfmAutoComplete {
|
|||
at: '#',
|
||||
alias: ISSUES_ALIAS,
|
||||
searchKey: 'search',
|
||||
maxLen: 100,
|
||||
displayTpl(value) {
|
||||
let tmpl = GfmAutoComplete.Loading.template;
|
||||
if (value.title != null) {
|
||||
|
|
@ -515,6 +520,7 @@ class GfmAutoComplete {
|
|||
searchKey: 'search',
|
||||
// eslint-disable-next-line no-template-curly-in-string
|
||||
insertTpl: '${atwho-at}${title}',
|
||||
maxLen: 100,
|
||||
displayTpl(value) {
|
||||
let tmpl = GfmAutoComplete.Loading.template;
|
||||
if (value.title != null) {
|
||||
|
|
@ -570,6 +576,7 @@ class GfmAutoComplete {
|
|||
at: '!',
|
||||
alias: MERGEREQUESTS_ALIAS,
|
||||
searchKey: 'search',
|
||||
maxLen: 100,
|
||||
displayTpl(value) {
|
||||
let tmpl = GfmAutoComplete.Loading.template;
|
||||
if (value.title != null) {
|
||||
|
|
@ -616,6 +623,7 @@ class GfmAutoComplete {
|
|||
alias: LABELS_ALIAS,
|
||||
searchKey: 'search',
|
||||
data: GfmAutoComplete.defaultLoadingData,
|
||||
maxLen: 100,
|
||||
displayTpl(value) {
|
||||
let tmpl = GfmAutoComplete.Labels.templateFunction(value.color, value.title);
|
||||
if (GfmAutoComplete.isLoading(value)) {
|
||||
|
|
@ -703,6 +711,7 @@ class GfmAutoComplete {
|
|||
at: '$',
|
||||
alias: SNIPPETS_ALIAS,
|
||||
searchKey: 'search',
|
||||
maxLen: 100,
|
||||
displayTpl(value) {
|
||||
let tmpl = GfmAutoComplete.Loading.template;
|
||||
if (value.title != null) {
|
||||
|
|
@ -741,6 +750,7 @@ class GfmAutoComplete {
|
|||
suffix: ']',
|
||||
alias: CONTACTS_ALIAS,
|
||||
searchKey: 'search',
|
||||
maxLen: 100,
|
||||
displayTpl(value) {
|
||||
let tmpl = GfmAutoComplete.Loading.template;
|
||||
if (value.email != null) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<!-- eslint-disable vue/multi-word-component-names -->
|
||||
<script>
|
||||
import { GlLoadingIcon, GlIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { GlButton, GlLoadingIcon, GlIcon, GlTooltipDirective } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
const MARK_TEXT = __('Mark as done');
|
||||
|
|
@ -8,6 +8,7 @@ const TODO_TEXT = __('Add a to do');
|
|||
|
||||
export default {
|
||||
components: {
|
||||
GlButton,
|
||||
GlIcon,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
|
|
@ -42,8 +43,11 @@ export default {
|
|||
computed: {
|
||||
buttonClasses() {
|
||||
return this.collapsed
|
||||
? 'btn-blank btn-todo sidebar-collapsed-icon js-dont-change-state'
|
||||
: 'gl-button btn btn-default btn-todo issuable-header-btn gl-float-right';
|
||||
? 'sidebar-collapsed-icon js-dont-change-state'
|
||||
: 'issuable-header-btn gl-float-right';
|
||||
},
|
||||
buttonVariant() {
|
||||
return this.collapsed ? 'link' : 'default';
|
||||
},
|
||||
buttonLabel() {
|
||||
return this.isTodo ? MARK_TEXT : TODO_TEXT;
|
||||
|
|
@ -70,13 +74,15 @@ export default {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<button
|
||||
<gl-button
|
||||
v-gl-tooltip.left.viewport
|
||||
:class="buttonClasses"
|
||||
:variant="buttonVariant"
|
||||
:title="buttonTooltip"
|
||||
:aria-label="buttonLabel"
|
||||
:data-issuable-id="issuableId"
|
||||
:data-issuable-type="issuableType"
|
||||
size="small"
|
||||
type="button"
|
||||
@click="handleButtonClick"
|
||||
>
|
||||
|
|
@ -85,7 +91,7 @@ export default {
|
|||
:class="collapsedButtonIconClasses"
|
||||
:name="collapsedButtonIcon"
|
||||
/>
|
||||
<span v-show="!collapsed" class="issuable-todo-inner">{{ buttonLabel }}</span>
|
||||
<gl-loading-icon v-show="isActionActive" size="sm" :inline="true" />
|
||||
</button>
|
||||
<span v-if="!collapsed" class="issuable-todo-inner">{{ buttonLabel }}</span>
|
||||
<gl-loading-icon v-if="isActionActive" size="sm" inline />
|
||||
</gl-button>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@ export default {
|
|||
v-for="option in defaultVisibilityLevels"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
class="mb-3"
|
||||
class="gl-mb-3"
|
||||
>
|
||||
<div class="d-flex gl-align-items-center">
|
||||
<div class="gl-display-flex gl-align-items-center">
|
||||
<gl-icon :size="16" :name="option.icon" />
|
||||
<span
|
||||
class="font-weight-bold ml-1 js-visibility-option"
|
||||
class="gl-font-weight-semibold gl-ml-2 js-visibility-option"
|
||||
data-testid="visibility-content"
|
||||
:data-qa-visibility="option.label"
|
||||
>{{ option.label }}</span
|
||||
|
|
@ -71,7 +71,7 @@ export default {
|
|||
</gl-form-radio-group>
|
||||
</gl-form-group>
|
||||
|
||||
<div class="text-muted" data-testid="restricted-levels-info">
|
||||
<div class="gl-text-secondary" data-testid="restricted-levels-info">
|
||||
<template v-if="!defaultVisibilityLevels.length">{{
|
||||
$options.SNIPPET_LEVELS_DISABLED
|
||||
}}</template>
|
||||
|
|
|
|||
|
|
@ -26,9 +26,6 @@ export default {
|
|||
|
||||
<template>
|
||||
<div class="block gl-display-flex gl-justify-content-space-between gl-border-b-gray-100!">
|
||||
<span class="issuable-header-text hide-collapsed">
|
||||
{{ __('To Do') }}
|
||||
</span>
|
||||
<sidebar-todo
|
||||
v-if="!sidebarCollapsed"
|
||||
:project-path="projectPath"
|
||||
|
|
|
|||
|
|
@ -138,8 +138,8 @@ export default {
|
|||
<template>
|
||||
<div
|
||||
:class="{
|
||||
'block todo': sidebarCollapsed,
|
||||
'gl-ml-auto': !sidebarCollapsed,
|
||||
block: sidebarCollapsed,
|
||||
'gl-display-inline-flex gl-flex-basis-full': !sidebarCollapsed,
|
||||
}"
|
||||
>
|
||||
<todo
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<script>
|
||||
import { GlAlert, GlButton, GlForm, GlFormGroup } from '@gitlab/ui';
|
||||
import { GlAlert, GlButton, GlForm, GlFormGroup, GlFormTextarea } from '@gitlab/ui';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
import { getDraft, clearDraft, updateDraft } from '~/lib/utils/autosave';
|
||||
|
|
@ -22,6 +22,7 @@ export default {
|
|||
GlButton,
|
||||
GlForm,
|
||||
GlFormGroup,
|
||||
GlFormTextarea,
|
||||
MarkdownEditor,
|
||||
WorkItemDescriptionRendered,
|
||||
},
|
||||
|
|
@ -312,11 +313,12 @@ export default {
|
|||
</p>
|
||||
<details class="gl-mb-5">
|
||||
<summary class="gl-text-blue-500">{{ s__('WorkItem|View current version') }}</summary>
|
||||
<textarea
|
||||
class="note-textarea js-gfm-input js-autosize markdown-area gl-p-3"
|
||||
<gl-form-textarea
|
||||
class="js-gfm-input js-autosize markdown-area gl-font-monospace!"
|
||||
data-testid="conflicted-description"
|
||||
readonly
|
||||
:value="conflictedDescription"
|
||||
></textarea>
|
||||
/>
|
||||
</details>
|
||||
<template #actions>
|
||||
<gl-button
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { isEmpty } from 'lodash';
|
||||
import { GlAlert, GlSkeletonLoader, GlButton, GlTooltipDirective, GlEmptyState } from '@gitlab/ui';
|
||||
import { GlAlert, GlButton, GlTooltipDirective, GlEmptyState } from '@gitlab/ui';
|
||||
import noAccessSvg from '@gitlab/svgs/dist/illustrations/analytics/no-access.svg?raw';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { s__ } from '~/locale';
|
||||
|
|
@ -46,6 +46,7 @@ import WorkItemRelationships from './work_item_relationships/work_item_relations
|
|||
import WorkItemStickyHeader from './work_item_sticky_header.vue';
|
||||
import WorkItemAncestors from './work_item_ancestors/work_item_ancestors.vue';
|
||||
import WorkItemTitleWithEdit from './work_item_title_with_edit.vue';
|
||||
import WorkItemLoading from './work_item_loading.vue';
|
||||
|
||||
export default {
|
||||
i18n,
|
||||
|
|
@ -56,7 +57,6 @@ export default {
|
|||
components: {
|
||||
GlAlert,
|
||||
GlButton,
|
||||
GlSkeletonLoader,
|
||||
GlEmptyState,
|
||||
WorkItemActions,
|
||||
WorkItemTodos,
|
||||
|
|
@ -74,6 +74,7 @@ export default {
|
|||
WorkItemStickyHeader,
|
||||
WorkItemAncestors,
|
||||
WorkItemTitleWithEdit,
|
||||
WorkItemLoading,
|
||||
},
|
||||
mixins: [glFeatureFlagMixin()],
|
||||
inject: ['fullPath', 'isGroup', 'reportAbusePath'],
|
||||
|
|
@ -428,11 +429,8 @@ export default {
|
|||
</gl-alert>
|
||||
</section>
|
||||
<section :class="workItemBodyClass">
|
||||
<div v-if="workItemLoading" class="gl-max-w-26 gl-py-5">
|
||||
<gl-skeleton-loader :height="65" :width="240">
|
||||
<rect width="240" height="20" x="5" y="0" rx="4" />
|
||||
<rect width="100" height="20" x="5" y="45" rx="4" />
|
||||
</gl-skeleton-loader>
|
||||
<div v-if="workItemLoading">
|
||||
<work-item-loading :two-column-view="workItemsBetaEnabled" />
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="gl-sm-display-none! gl-display-flex">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,135 @@
|
|||
<script>
|
||||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
|
||||
export default {
|
||||
name: 'WorkItemLoading',
|
||||
loader: {
|
||||
repeat: 10,
|
||||
width: 1000,
|
||||
height: 40,
|
||||
descriptionRepeat: 2,
|
||||
attributesRepeat: 6,
|
||||
},
|
||||
components: {
|
||||
GlSkeletonLoader,
|
||||
},
|
||||
props: {
|
||||
twoColumnView: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="twoColumnView" class="work-item-overview" data-testid="work-item-two-column-loading">
|
||||
<section>
|
||||
<gl-skeleton-loader :height="60" :width="600" data-testid="work-title-and-meta-loading">
|
||||
<!--- START work item title -->
|
||||
<rect width="500" height="20" x="5" y="0" rx="4" />
|
||||
<!--- END work item title -->
|
||||
<!--- START work item meta -->
|
||||
<rect width="50" height="15" x="5" y="30" rx="6" />
|
||||
<rect width="150" height="5" x="60" y="35" rx="2" />
|
||||
<!--- END work item meta -->
|
||||
</gl-skeleton-loader>
|
||||
|
||||
<!--- START work item description -->
|
||||
<div data-testid="work-item-description-loading">
|
||||
<gl-skeleton-loader
|
||||
v-for="i in $options.loader.descriptionRepeat"
|
||||
:key="i"
|
||||
:width="600"
|
||||
:height="20"
|
||||
>
|
||||
<rect width="500" x="5" y="0" height="5" rx="2" />
|
||||
<rect width="595" x="5" y="10" height="5" rx="2" />
|
||||
</gl-skeleton-loader>
|
||||
|
||||
<gl-skeleton-loader :width="600" :height="20">
|
||||
<rect width="300" x="5" y="0" height="5" rx="2" />
|
||||
</gl-skeleton-loader>
|
||||
|
||||
<gl-skeleton-loader :width="600" :height="20">
|
||||
<rect width="500" x="5" y="0" height="5" rx="2" />
|
||||
<rect width="595" x="5" y="10" height="5" rx="2" />
|
||||
</gl-skeleton-loader>
|
||||
|
||||
<gl-skeleton-loader :width="600" :height="20">
|
||||
<rect width="300" x="5" y="0" height="5" rx="2" />
|
||||
</gl-skeleton-loader>
|
||||
</div>
|
||||
<!--- END work item description -->
|
||||
|
||||
<!--- START work item attributes wrapper small/xs screen -->
|
||||
<div
|
||||
class="work-item-attributes-wrapper gl-md-display-none!"
|
||||
data-testid="work-item-attributes-xssm-loading"
|
||||
>
|
||||
<gl-skeleton-loader
|
||||
v-for="i in $options.loader.attributesRepeat"
|
||||
:key="i"
|
||||
:width="240"
|
||||
:height="20"
|
||||
>
|
||||
<rect width="50" x="2" y="0" height="2" rx="1" />
|
||||
<rect width="100" x="2" y="5" height="4" rx="1" />
|
||||
</gl-skeleton-loader>
|
||||
</div>
|
||||
<!--- END work item attributes wrapper small/xs screen -->
|
||||
|
||||
<!--- START work item notes activity placeholder -->
|
||||
<gl-skeleton-loader
|
||||
:height="30"
|
||||
:width="600"
|
||||
data-testid="work-item-activity-placeholder-loading"
|
||||
>
|
||||
<rect width="100" height="15" x="5" y="0" rx="4" />
|
||||
</gl-skeleton-loader>
|
||||
<!--- END work item notes activity placeholder -->
|
||||
|
||||
<!--- START work item notes -->
|
||||
<gl-skeleton-loader
|
||||
v-for="i in $options.loader.repeat"
|
||||
:key="i"
|
||||
data-testid="work-item-notes-loading"
|
||||
:width="$options.loader.width"
|
||||
:height="$options.loader.height"
|
||||
preserve-aspect-ratio="xMinYMax meet"
|
||||
>
|
||||
<circle cx="20" cy="20" r="16" />
|
||||
<rect width="950" x="45" y="15" height="10" rx="4" />
|
||||
</gl-skeleton-loader>
|
||||
<!--- END work item notes -->
|
||||
</section>
|
||||
|
||||
<!--- START work item attributes wrapper md/lg screens -->
|
||||
<aside
|
||||
class="work-item-overview-right-sidebar gl-md-display-block! gl-display-none"
|
||||
data-testid="work-item-attributes-mdup-loading"
|
||||
>
|
||||
<div class="work-item-attributes-wrapper">
|
||||
<gl-skeleton-loader
|
||||
v-for="i in $options.loader.attributesRepeat"
|
||||
:key="i"
|
||||
:width="240"
|
||||
:height="50"
|
||||
>
|
||||
<rect width="100" x="0" y="25" height="5" rx="4" />
|
||||
<rect width="240" x="0" y="35" height="10" rx="4" />
|
||||
</gl-skeleton-loader>
|
||||
</div>
|
||||
</aside>
|
||||
<!--- END work item attributes wrapper md/lg screens -->
|
||||
</div>
|
||||
<div v-else data-testid="work-item-single-column-loading" class="gl-max-w-26 gl-py-5">
|
||||
<!--- START work item loading original loader -->
|
||||
<gl-skeleton-loader :height="65" :width="240">
|
||||
<rect width="240" height="20" x="5" y="0" rx="4" />
|
||||
<rect width="100" height="20" x="5" y="45" rx="4" />
|
||||
</gl-skeleton-loader>
|
||||
<!--- END work item loading original loader -->
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -349,14 +349,14 @@ export default {
|
|||
/>
|
||||
<div v-if="initialLoading" class="gl-mt-5">
|
||||
<gl-skeleton-loader
|
||||
v-for="index in $options.loader.repeat"
|
||||
:key="index"
|
||||
:width="$options.loader.width"
|
||||
v-for="i in $options.loader.repeat"
|
||||
:key="i"
|
||||
:width="1000"
|
||||
:height="$options.loader.height"
|
||||
preserve-aspect-ratio="xMinYMax meet"
|
||||
>
|
||||
<circle cx="20" cy="20" r="16" />
|
||||
<rect width="500" x="45" y="15" height="10" rx="4" />
|
||||
<rect width="950" x="45" y="15" height="10" rx="4" />
|
||||
</gl-skeleton-loader>
|
||||
</div>
|
||||
<div v-else class="issuable-discussion gl-mb-5 gl-clearfix!">
|
||||
|
|
|
|||
|
|
@ -392,10 +392,6 @@
|
|||
margin-left: $gl-spacing-scale-3;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.user-access-role {
|
||||
line-height: $gl-line-height-14;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(md) {
|
||||
|
|
@ -476,7 +472,7 @@
|
|||
.form-control {
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
|
||||
&.form-group {
|
||||
@include media-breakpoint-up(sm) {
|
||||
margin-bottom: 0;
|
||||
|
|
|
|||
|
|
@ -80,18 +80,6 @@ table.pipeline-project-metrics tr td {
|
|||
}
|
||||
}
|
||||
|
||||
.user-access-role {
|
||||
padding-left: $gl-spacing-scale-3;
|
||||
padding-right: $gl-spacing-scale-3;
|
||||
display: inline-block;
|
||||
color: $gl-text-color-secondary;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: $label-border-radius;
|
||||
font-weight: $gl-font-weight-normal;
|
||||
}
|
||||
|
||||
.groups-list-tree-container {
|
||||
> .group-list-tree > .group-row.has-children:first-child {
|
||||
border-top: 0;
|
||||
|
|
|
|||
|
|
@ -120,8 +120,11 @@ module Auth
|
|||
end
|
||||
end
|
||||
|
||||
# Return the project path (lowercase) as metadata
|
||||
{ project_path: project&.full_path&.downcase }
|
||||
{
|
||||
project_path: project&.full_path&.downcase,
|
||||
project_id: project&.id,
|
||||
root_namespace_id: project&.root_ancestor&.id
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
- access = note_human_max_access(note)
|
||||
- if note.noteable_author?(@noteable)
|
||||
%span{ class: 'note-role user-access-role has-tooltip d-none d-md-inline-block', title: _("This user is the author of this %{noteable}.") % { noteable: @noteable.human_class_name } }= _("Author")
|
||||
= render Pajamas::BadgeComponent.new(_("Author"), variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100! note-role user-access-role has-tooltip gl-display-none gl-md-display-inline-block', title: _("This user is the author of this %{noteable}.") % { noteable: @noteable.human_class_name })
|
||||
- if access
|
||||
%span{ class: 'note-role user-access-role has-tooltip', title: _("This user has the %{access} role in the %{name} project.") % { access: access.downcase, name: note.project_name } }= access
|
||||
= render Pajamas::BadgeComponent.new(access, variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100! note-role user-access-role has-tooltip', title: _("This user has the %{access} role in the %{name} project.") % { access: access.downcase, name: note.project_name })
|
||||
- elsif note.contributor?
|
||||
%span{ class: 'note-role user-access-role has-tooltip', title: _("This user has previously committed to the %{name} project.") % { name: note.project_name } }= _("Contributor")
|
||||
= render Pajamas::BadgeComponent.new(_("Contributor"), variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100! note-role user-access-role has-tooltip', title: _("This user has previously committed to the %{name} project.") % { name: note.project_name })
|
||||
|
||||
- if can?(current_user, :award_emoji, note)
|
||||
- if note.emoji_awardable?
|
||||
|
|
|
|||
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
%h1.page-title.gl-font-size-h-display
|
||||
= _("Edit Snippet")
|
||||
%hr
|
||||
|
||||
= render "shared/snippets/form", url: project_snippet_path(@project, @snippet)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
= link_to group.full_name, group, class: 'group-name'
|
||||
|
||||
- if access&.nonzero?
|
||||
%span.user-access-role= Gitlab::Access.human_access(access)
|
||||
= render Pajamas::BadgeComponent.new(Gitlab::Access.human_access(access), variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100!')
|
||||
|
||||
- if group.description.present?
|
||||
.description
|
||||
|
|
|
|||
|
|
@ -61,4 +61,4 @@
|
|||
- if show_roles
|
||||
.controls.member-controls.gl-align-items-center
|
||||
= render_if_exists 'shared/members/ee/ldap_tag', can_override: member.can_override?
|
||||
%span.member-access-text.user-access-role= member.human_access
|
||||
= render Pajamas::BadgeComponent.new(member.human_access, variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100!')
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
- if !explore_projects_tab? && access&.nonzero?
|
||||
-# haml-lint:disable UnnecessaryStringOutput
|
||||
= ' ' # prevent haml from eating the space between elements
|
||||
%span.user-access-role.gl-display-block.gl-m-0{ data: { testid: 'user-role-content' } }= localized_project_human_access(access)
|
||||
= render Pajamas::BadgeComponent.new(localized_project_human_access(access), variant: 'neutral', class: 'gl-bg-transparent! gl-inset-border-1-gray-100!', data: { testid: 'user-access-role' })
|
||||
|
||||
- if !explore_projects_tab?
|
||||
= render_if_exists 'compliance_management/compliance_framework/compliance_framework_badge', project: project, additional_classes: 'gl-ml-2!'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
# Use this template to announce a feature deprecation or other
|
||||
# important planned changes at least three releases prior to removal.
|
||||
# Breaking changes must happen in a major release.
|
||||
#
|
||||
# See the deprecation guidelines to confirm your understanding of GitLab's definitions:
|
||||
# https://docs.gitlab.com/ee/development/deprecation_guidelines/#terminology
|
||||
#
|
||||
# If an End of Support period applies, see the OPTIONAL section below.
|
||||
#
|
||||
# For more information, see the handbook:
|
||||
# https://handbook.gitlab.com/handbook/marketing/blog/release-posts/#deprecations-and-other-planned-breaking-change-announcements
|
||||
|
||||
# ===================
|
||||
# REQUIRED FIELDS
|
||||
# ===================
|
||||
|
||||
# ----- DELETE EVERYTHING ABOVE THIS LINE -----
|
||||
|
||||
- title: "Hosted Runners on Linux operating system upgrade"
|
||||
# The milestones for the deprecation announcement, and the removal.
|
||||
removal_milestone: "17.0"
|
||||
announcement_milestone: "16.10"
|
||||
# Change breaking_change to false if needed.
|
||||
breaking_change: true
|
||||
# The stage and GitLab username of the person reporting the change,
|
||||
# and a link to the deprecation issue
|
||||
reporter: tmaczukin
|
||||
stage: ci
|
||||
issue_url: https://gitlab.com/gitlab-org/ci-cd/shared-runners/infrastructure/-/issues/60
|
||||
impact: low # Can be one of: [critical, high, medium, low]
|
||||
scope: instance # Can be one or a combination of: [instance, group, project]
|
||||
resolution_role: Developer # Can be one of: [Admin, Owner, Maintainer, Developer]
|
||||
manual_task: true # Can be true or false. Use this to denote whether a resolution action must be performed manually (true), or if it can be automated by using the API or other automation (false).
|
||||
body: | # (required) Don't change this line.
|
||||
With GitLab 17.0 we're upgrading the container-optimized operating system ([COS](https://cloud.google.com/container-optimized-os/docs))
|
||||
of the ephemeral VMs used to execute jobs for [Hosted Runners on Linux](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html).
|
||||
The COS upgrade includes a Docker Engine upgrade from Version 19.03.15 to Version 23.0.5, which introduced
|
||||
a known compatibility issue.
|
||||
|
||||
GitLab CI/CD jobs [using Docker-in-Docker-based jobs](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker)
|
||||
with a Docker-in-Docker service version prior to 20.10 and GitLab CI/CD jobs [using Kaniko to build container images](https://docs.gitlab.com/ee/ci/docker/using_kaniko.html)
|
||||
with a Kaniko service version older than `v1.9.0` will start failing.
|
||||
|
||||
To fix these issues, an update of service version in `.gitlab-ci.yml` is required.
|
||||
|
||||
Both issues, including a detailed explanation of how they affect jobs and how to fix
|
||||
the issue, are described
|
||||
[in the announcement blog post](https://about.gitlab.com/blog/2023/10/04/updating-the-os-version-of-saas-runners-on-linux/).
|
||||
|
||||
# ==============================
|
||||
# OPTIONAL END-OF-SUPPORT FIELDS
|
||||
# ==============================
|
||||
#
|
||||
# If an End of Support period applies:
|
||||
# 1) Share this announcement in the `#spt_managers` Support channel in Slack
|
||||
# 2) Mention `@gitlab-com/support` in this merge request.
|
||||
#
|
||||
# When support for this feature ends, in XX.YY milestone format.
|
||||
end_of_support_milestone:
|
||||
# Array of tiers the feature is currently available to,
|
||||
# like [Free, Silver, Gold, Core, Premium, Ultimate]
|
||||
tiers:
|
||||
# Links to documentation and thumbnail image
|
||||
documentation_url:
|
||||
image_url:
|
||||
# Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
|
||||
video_url:
|
||||
|
|
@ -1241,6 +1241,33 @@ set `AUTO_DEVOPS_BUILD_IMAGE_CNB_BUILDER` to `heroku/builder:20`.
|
|||
|
||||
<div class="deprecation breaking-change" data-milestone="17.0">
|
||||
|
||||
### Hosted Runners on Linux operating system upgrade
|
||||
|
||||
<div class="deprecation-notes">
|
||||
- Announced in GitLab <span class="milestone">16.10</span>
|
||||
- Removal in GitLab <span class="milestone">17.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
|
||||
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/ci-cd/shared-runners/infrastructure/-/issues/60).
|
||||
</div>
|
||||
|
||||
With GitLab 17.0 we're upgrading the container-optimized operating system ([COS](https://cloud.google.com/container-optimized-os/docs))
|
||||
of the ephemeral VMs used to execute jobs for [Hosted Runners on Linux](https://docs.gitlab.com/ee/ci/runners/saas/linux_saas_runner.html).
|
||||
The COS upgrade includes a Docker Engine upgrade from Version 19.03.15 to Version 23.0.5, which introduced
|
||||
a known compatibility issue.
|
||||
|
||||
GitLab CI/CD jobs [using Docker-in-Docker-based jobs](https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#use-docker-in-docker)
|
||||
with a Docker-in-Docker service version prior to 20.10 and GitLab CI/CD jobs [using Kaniko to build container images](https://docs.gitlab.com/ee/ci/docker/using_kaniko.html)
|
||||
with a Kaniko service version older than `v1.9.0` will start failing.
|
||||
|
||||
To fix these issues, an update of service version in `.gitlab-ci.yml` is required.
|
||||
|
||||
Both issues, including a detailed explanation of how they affect jobs and how to fix
|
||||
the issue, are described
|
||||
[in the announcement blog post](https://about.gitlab.com/blog/2023/10/04/updating-the-os-version-of-saas-runners-on-linux/).
|
||||
|
||||
</div>
|
||||
|
||||
<div class="deprecation breaking-change" data-milestone="17.0">
|
||||
|
||||
### Internal container registry API tag deletion endpoint
|
||||
|
||||
<div class="deprecation-notes">
|
||||
|
|
|
|||
|
|
@ -165,10 +165,26 @@ pull-image:
|
|||
- docker pull $GOOGLE_ARTIFACT_REGISTRY_REPOSITORY_LOCATION-docker.pkg.dev/$GOOGLE_ARTIFACT_REGISTRY_PROJECT_ID/$GOOGLE_ARTIFACT_REGISTRY_REPOSITORY_NAME/app:v0.1.0
|
||||
```
|
||||
|
||||
### Copy an image from the GitLab Container Registry with Docker
|
||||
#### Copy an image by using a CI/CD component
|
||||
|
||||
The following example shows how to replicate an image from the GitLab Container Registry to the Google Artifact Registry.
|
||||
To do this, pull the image from GitLab, re-tag it, and then push to the Google Artifact Registry.
|
||||
Google provides the [`upload-artifact-registry`](https://gitlab.com/explore/catalog/google-gitlab-components/artifact-registry) CI/CD component, which you can use to copy an image from the GitLab container registry to Artifact Registry.
|
||||
|
||||
To use the `upload-artifact-registry` component, add the following to your `.gitlab-ci.yml`:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
- component: gitlab.com/google-gitlab-components/artifact-registry/upload-artifact-registry@<VERSION>
|
||||
inputs:
|
||||
stage: deploy
|
||||
source: $CI_REGISTRY_IMAGE:v0.1.0
|
||||
target: $GOOGLE_ARTIFACT_REGISTRY_REPOSITORY_LOCATION-docker.pkg.dev/$GOOGLE_ARTIFACT_REGISTRY_PROJECT_ID/$GOOGLE_ARTIFACT_REGISTRY_REPOSITORY_NAME/app:v0.1.0
|
||||
```
|
||||
|
||||
For details, see [the component documentation](https://gitlab.com/explore/catalog/google-gitlab-components/artifact-registry).
|
||||
|
||||
Using the `upload-artifact-registry` component simplifies copying images to Artifact Registry and is the intended method for this integration. If you want to use Docker or Crane, see the following examples.
|
||||
|
||||
#### Copy an image by using Docker
|
||||
|
||||
In the following example, the `gcloud` CLI is used to set up the Docker authentication, as an alternative to the [standalone Docker credential helper](https://cloud.google.com/artifact-registry/docs/docker/authentication#standalone-helper).
|
||||
|
||||
|
|
@ -191,7 +207,7 @@ copy-image:
|
|||
- docker push $TARGET_IMAGE
|
||||
```
|
||||
|
||||
### Copy an image from the GitLab Container Registry with crane
|
||||
#### Copy an image by using Crane
|
||||
|
||||
```yaml
|
||||
copy-image:
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ module QA
|
|||
|
||||
view 'app/views/shared/projects/_project.html.haml' do
|
||||
element 'project-content'
|
||||
element 'user-role-content'
|
||||
element 'user-access-role'
|
||||
end
|
||||
|
||||
view 'app/views/dashboard/_projects_head.html.haml' do
|
||||
|
|
@ -62,7 +62,7 @@ module QA
|
|||
|
||||
def has_project_with_access_role?(project_name, access_role)
|
||||
within_element('project-content', text: project_name) do
|
||||
has_element?('user-role-content', text: access_role)
|
||||
has_element?('user-access-role', text: access_role)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ RSpec.describe 'Dashboard Projects', :js, feature_category: :groups_and_projects
|
|||
it 'shows role badge' do
|
||||
visit dashboard_projects_path
|
||||
|
||||
page.within '.user-access-role' do
|
||||
within_testid('user-access-role') do
|
||||
expect(page).to have_content('Developer')
|
||||
end
|
||||
end
|
||||
|
|
@ -39,7 +39,7 @@ RSpec.describe 'Dashboard Projects', :js, feature_category: :groups_and_projects
|
|||
it 'displays the right role' do
|
||||
visit dashboard_projects_path
|
||||
|
||||
page.within '.user-access-role' do
|
||||
within_testid('user-access-role') do
|
||||
expect(page).to have_content('Developer')
|
||||
end
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ RSpec.describe 'Dashboard Projects', :js, feature_category: :groups_and_projects
|
|||
|
||||
visit dashboard_projects_path
|
||||
|
||||
page.within '.user-access-role' do
|
||||
within_testid('user-access-role') do
|
||||
expect(page).to have_content('Maintainer')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,12 +1,17 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`SidebarTodo template renders component container element with proper data attributes 1`] = `
|
||||
<button
|
||||
<gl-button-stub
|
||||
aria-label="Mark as done"
|
||||
class="btn btn-default btn-todo gl-button gl-float-right issuable-header-btn"
|
||||
buttontextclasses=""
|
||||
category="primary"
|
||||
class="gl-float-right issuable-header-btn"
|
||||
data-issuable-id="1"
|
||||
data-issuable-type="epic"
|
||||
icon=""
|
||||
size="small"
|
||||
type="button"
|
||||
variant="default"
|
||||
>
|
||||
<gl-icon-stub
|
||||
class="todo-undone"
|
||||
|
|
@ -19,13 +24,5 @@ exports[`SidebarTodo template renders component container element with proper da
|
|||
>
|
||||
Mark as done
|
||||
</span>
|
||||
<gl-loading-icon-stub
|
||||
color="dark"
|
||||
inline="true"
|
||||
label="Loading"
|
||||
size="sm"
|
||||
style="display: none;"
|
||||
variant="spinner"
|
||||
/>
|
||||
</button>
|
||||
</gl-button-stub>
|
||||
`;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
|
||||
import { GlButton, GlLoadingIcon, GlIcon } from '@gitlab/ui';
|
||||
import { shallowMount } from '@vue/test-utils';
|
||||
|
||||
import { nextTick } from 'vue';
|
||||
|
|
@ -20,14 +20,15 @@ describe('SidebarTodo', () => {
|
|||
},
|
||||
});
|
||||
};
|
||||
const findButton = () => wrapper.findComponent(GlButton);
|
||||
|
||||
it.each`
|
||||
state | classes
|
||||
${false} | ${['gl-button', 'btn', 'btn-default', 'btn-todo', 'issuable-header-btn', 'gl-float-right']}
|
||||
${true} | ${['btn-blank', 'btn-todo', 'sidebar-collapsed-icon', 'js-dont-change-state']}
|
||||
${false} | ${['issuable-header-btn', 'gl-float-right']}
|
||||
${true} | ${['sidebar-collapsed-icon', 'js-dont-change-state']}
|
||||
`('returns todo button classes for when `collapsed` prop is `$state`', ({ state, classes }) => {
|
||||
createComponent({ collapsed: state });
|
||||
expect(wrapper.find('button').classes()).toStrictEqual(classes);
|
||||
expect(findButton().classes()).toStrictEqual(classes);
|
||||
});
|
||||
|
||||
it.each`
|
||||
|
|
@ -41,14 +42,14 @@ describe('SidebarTodo', () => {
|
|||
|
||||
expect(wrapper.findComponent(GlIcon).classes().join(' ')).toStrictEqual(iconClass);
|
||||
expect(wrapper.findComponent(GlIcon).props('name')).toStrictEqual(icon);
|
||||
expect(wrapper.find('button').text()).toBe(label);
|
||||
expect(findButton().text()).toBe(label);
|
||||
},
|
||||
);
|
||||
|
||||
describe('template', () => {
|
||||
it('emits `toggleTodo` event when clicked on button', async () => {
|
||||
createComponent();
|
||||
wrapper.find('button').trigger('click');
|
||||
findButton().vm.$emit('click');
|
||||
|
||||
await nextTick();
|
||||
expect(wrapper.emitted().toggleTodo).toHaveLength(1);
|
||||
|
|
|
|||
|
|
@ -32,18 +32,18 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
|
|||
valuefield="value"
|
||||
>
|
||||
<gl-form-radio-stub
|
||||
class="mb-3"
|
||||
class="gl-mb-3"
|
||||
value="private"
|
||||
>
|
||||
<div
|
||||
class="d-flex gl-align-items-center"
|
||||
class="gl-align-items-center gl-display-flex"
|
||||
>
|
||||
<gl-icon-stub
|
||||
name="lock"
|
||||
size="16"
|
||||
/>
|
||||
<span
|
||||
class="font-weight-bold js-visibility-option ml-1"
|
||||
class="gl-font-weight-semibold gl-ml-2 js-visibility-option"
|
||||
data-qa-visibility="Private"
|
||||
data-testid="visibility-content"
|
||||
>
|
||||
|
|
@ -52,18 +52,18 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
|
|||
</div>
|
||||
</gl-form-radio-stub>
|
||||
<gl-form-radio-stub
|
||||
class="mb-3"
|
||||
class="gl-mb-3"
|
||||
value="internal"
|
||||
>
|
||||
<div
|
||||
class="d-flex gl-align-items-center"
|
||||
class="gl-align-items-center gl-display-flex"
|
||||
>
|
||||
<gl-icon-stub
|
||||
name="shield"
|
||||
size="16"
|
||||
/>
|
||||
<span
|
||||
class="font-weight-bold js-visibility-option ml-1"
|
||||
class="gl-font-weight-semibold gl-ml-2 js-visibility-option"
|
||||
data-qa-visibility="Internal"
|
||||
data-testid="visibility-content"
|
||||
>
|
||||
|
|
@ -72,18 +72,18 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
|
|||
</div>
|
||||
</gl-form-radio-stub>
|
||||
<gl-form-radio-stub
|
||||
class="mb-3"
|
||||
class="gl-mb-3"
|
||||
value="public"
|
||||
>
|
||||
<div
|
||||
class="d-flex gl-align-items-center"
|
||||
class="gl-align-items-center gl-display-flex"
|
||||
>
|
||||
<gl-icon-stub
|
||||
name="earth"
|
||||
size="16"
|
||||
/>
|
||||
<span
|
||||
class="font-weight-bold js-visibility-option ml-1"
|
||||
class="gl-font-weight-semibold gl-ml-2 js-visibility-option"
|
||||
data-qa-visibility="Public"
|
||||
data-testid="visibility-content"
|
||||
>
|
||||
|
|
@ -94,7 +94,7 @@ exports[`Snippet Visibility Edit component rendering matches the snapshot 1`] =
|
|||
</gl-form-radio-group-stub>
|
||||
</gl-form-group-stub>
|
||||
<div
|
||||
class="text-muted"
|
||||
class="gl-text-secondary"
|
||||
data-testid="restricted-levels-info"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GlAlert, GlSkeletonLoader, GlEmptyState } from '@gitlab/ui';
|
||||
import { GlAlert, GlEmptyState } from '@gitlab/ui';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
|
|
@ -7,6 +7,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
|
|||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import setWindowLocation from 'helpers/set_window_location_helper';
|
||||
import { stubComponent } from 'helpers/stub_component';
|
||||
import WorkItemLoading from '~/work_items/components/work_item_loading.vue';
|
||||
import WorkItemDetail from '~/work_items/components/work_item_detail.vue';
|
||||
import WorkItemActions from '~/work_items/components/work_item_actions.vue';
|
||||
import WorkItemAncestors from '~/work_items/components/work_item_ancestors/work_item_ancestors.vue';
|
||||
|
|
@ -72,7 +73,7 @@ describe('WorkItemDetail component', () => {
|
|||
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
const findEmptyState = () => wrapper.findComponent(GlEmptyState);
|
||||
const findSkeleton = () => wrapper.findComponent(GlSkeletonLoader);
|
||||
const findWorkItemLoading = () => wrapper.findComponent(WorkItemLoading);
|
||||
const findWorkItemActions = () => wrapper.findComponent(WorkItemActions);
|
||||
const findWorkItemTitle = () => wrapper.findComponent(WorkItemTitle);
|
||||
const findCreatedUpdated = () => wrapper.findComponent(WorkItemCreatedUpdated);
|
||||
|
|
@ -181,7 +182,7 @@ describe('WorkItemDetail component', () => {
|
|||
});
|
||||
|
||||
it('renders skeleton loader', () => {
|
||||
expect(findSkeleton().exists()).toBe(true);
|
||||
expect(findWorkItemLoading().exists()).toBe(true);
|
||||
expect(findWorkItemTitle().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
@ -193,7 +194,7 @@ describe('WorkItemDetail component', () => {
|
|||
});
|
||||
|
||||
it('does not render skeleton', () => {
|
||||
expect(findSkeleton().exists()).toBe(false);
|
||||
expect(findWorkItemLoading().exists()).toBe(false);
|
||||
expect(findWorkItemTitle().exists()).toBe(true);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
import { GlSkeletonLoader } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import WorkItemLoading from '~/work_items/components/work_item_loading.vue';
|
||||
|
||||
describe('Work Item Loading spec', () => {
|
||||
let wrapper;
|
||||
|
||||
const findWorkItemTwoColumnLoading = () => wrapper.findByTestId('work-item-two-column-loading');
|
||||
const findWorkItemSingleColumnLoading = () =>
|
||||
wrapper.findByTestId('work-item-single-column-loading');
|
||||
const findWorkItemTitleMetaLoading = () => wrapper.findByTestId('work-title-and-meta-loading');
|
||||
const findWorkItemDescriptionLoading = () =>
|
||||
wrapper.findByTestId('work-item-description-loading');
|
||||
const findWorkItemAttributesXsSmLoading = () =>
|
||||
wrapper.findByTestId('work-item-attributes-xssm-loading');
|
||||
const findWorkItemAttributesMdUpLoading = () =>
|
||||
wrapper.findByTestId('work-item-attributes-mdup-loading');
|
||||
const findWorkItemActivityPlaceholder = () =>
|
||||
wrapper.findByTestId('work-item-activity-placeholder-loading');
|
||||
const findWorkItemNotesLoading = () => wrapper.findByTestId('work-item-notes-loading');
|
||||
const findLoaders = () => findWorkItemAttributesXsSmLoading().findAllComponents(GlSkeletonLoader);
|
||||
|
||||
const createComponent = ({ twoColumnView = false } = {}) => {
|
||||
wrapper = shallowMountExtended(WorkItemLoading, {
|
||||
propsData: {
|
||||
twoColumnView,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
describe('Work Item Single Column loading view', () => {
|
||||
beforeEach(() => {
|
||||
createComponent();
|
||||
});
|
||||
|
||||
it('renders the single column loading', () => {
|
||||
expect(findWorkItemSingleColumnLoading().exists()).toBe(true);
|
||||
expect(findWorkItemTwoColumnLoading().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Work Item Two Column loading view', () => {
|
||||
beforeEach(() => {
|
||||
createComponent({ twoColumnView: true });
|
||||
});
|
||||
|
||||
it('renders the two column loading', () => {
|
||||
expect(findWorkItemTwoColumnLoading().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders the title and meta loading skeleton', () => {
|
||||
expect(findWorkItemTitleMetaLoading().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders the description loading skeleton', () => {
|
||||
expect(findWorkItemDescriptionLoading().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders the attributes loading skeleton', () => {
|
||||
expect(findWorkItemAttributesXsSmLoading().exists()).toBe(true);
|
||||
expect(findWorkItemAttributesMdUpLoading().exists()).toBe(true);
|
||||
expect(findLoaders()).toHaveLength(WorkItemLoading.loader.attributesRepeat);
|
||||
});
|
||||
|
||||
it('renders the activity placeholder loading skeleton', () => {
|
||||
expect(findWorkItemActivityPlaceholder().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('renders the notes loading skeleton', () => {
|
||||
expect(findWorkItemNotesLoading().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -9,6 +9,7 @@ RSpec.shared_examples 'autocompletes items' do
|
|||
create(:milestone, project: project, title: 'My Cool Milestone')
|
||||
|
||||
project.add_maintainer(create(:user, name: 'JohnDoe123'))
|
||||
project.add_maintainer(create(:user, name: 'ReallyLongUsername1234567890'))
|
||||
else # group wikis
|
||||
project = create(:project, group: group)
|
||||
|
||||
|
|
@ -18,6 +19,7 @@ RSpec.shared_examples 'autocompletes items' do
|
|||
create(:milestone, group: group, title: 'My Cool Milestone')
|
||||
|
||||
project.add_maintainer(create(:user, name: 'JohnDoe123'))
|
||||
project.add_maintainer(create(:user, name: 'ReallyLongUsername1234567890'))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -40,4 +42,10 @@ RSpec.shared_examples 'autocompletes items' do
|
|||
fill_in :wiki_content, with: ':smil'
|
||||
expect(page).to have_text 'smile_cat'
|
||||
end
|
||||
|
||||
it 'autocompletes items with long names' do
|
||||
fill_in :wiki_content, with: "@ReallyLongUsername1234567"
|
||||
|
||||
expect(page).to have_text 'ReallyLongUsername1234567890'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -176,6 +176,7 @@ RSpec.shared_examples 'User creates wiki page' do
|
|||
end
|
||||
|
||||
it_behaves_like 'wiki file attachments'
|
||||
it_behaves_like 'autocompletes items'
|
||||
end
|
||||
|
||||
context "when wiki is not empty", :js do
|
||||
|
|
|
|||
|
|
@ -505,6 +505,9 @@ RSpec.shared_examples 'work items description' do
|
|||
|
||||
expect(page).to have_text(expected_warning)
|
||||
|
||||
page.find('summary', text: 'View current version').click
|
||||
expect(find_by_testid('conflicted-description').value).to eq('oh no!')
|
||||
|
||||
click_button s_('WorkItem|Save and overwrite')
|
||||
|
||||
expect(page.find('[data-testid="work-item-description"]')).to have_text("oh yeah!")
|
||||
|
|
|
|||
|
|
@ -86,7 +86,11 @@ RSpec.shared_examples 'an accessible' do
|
|||
[{ 'type' => 'repository',
|
||||
'name' => project.full_path,
|
||||
'actions' => actions,
|
||||
'meta' => { 'project_path' => project.full_path } }]
|
||||
'meta' => {
|
||||
'project_path' => project.full_path,
|
||||
'project_id' => project.id,
|
||||
'root_namespace_id' => project.root_ancestor.id
|
||||
} }]
|
||||
end
|
||||
|
||||
it_behaves_like 'a valid token'
|
||||
|
|
@ -252,13 +256,21 @@ RSpec.shared_examples 'a container registry auth service' do
|
|||
'type' => 'repository',
|
||||
'name' => project.full_path,
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => project.full_path }
|
||||
'meta' => {
|
||||
'project_path' => project.full_path,
|
||||
'project_id' => project.id,
|
||||
'root_namespace_id' => project.root_ancestor.id
|
||||
}
|
||||
},
|
||||
{
|
||||
'type' => 'repository',
|
||||
'name' => "#{project.full_path}/*",
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => project.full_path }
|
||||
'meta' => {
|
||||
'project_path' => project.full_path,
|
||||
'project_id' => project.id,
|
||||
'root_namespace_id' => project.root_ancestor.id
|
||||
}
|
||||
}
|
||||
]
|
||||
end
|
||||
|
|
@ -880,19 +892,35 @@ RSpec.shared_examples 'a container registry auth service' do
|
|||
{ 'type' => 'repository',
|
||||
'name' => internal_project.full_path,
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => internal_project.full_path } },
|
||||
'meta' => {
|
||||
'project_path' => internal_project.full_path,
|
||||
'project_id' => internal_project.id,
|
||||
'root_namespace_id' => internal_project.root_ancestor.id
|
||||
} },
|
||||
{ 'type' => 'repository',
|
||||
'name' => private_project.full_path,
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => private_project.full_path } },
|
||||
'meta' => {
|
||||
'project_path' => private_project.full_path,
|
||||
'project_id' => private_project.id,
|
||||
'root_namespace_id' => private_project.root_ancestor.id
|
||||
} },
|
||||
{ 'type' => 'repository',
|
||||
'name' => public_project.full_path,
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => public_project.full_path } },
|
||||
'meta' => {
|
||||
'project_path' => public_project.full_path,
|
||||
'project_id' => public_project.id,
|
||||
'root_namespace_id' => public_project.root_ancestor.id
|
||||
} },
|
||||
{ 'type' => 'repository',
|
||||
'name' => public_project_private_container_registry.full_path,
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => public_project_private_container_registry.full_path } }
|
||||
'meta' => {
|
||||
'project_path' => public_project_private_container_registry.full_path,
|
||||
'project_id' => public_project_private_container_registry.id,
|
||||
'root_namespace_id' => public_project_private_container_registry.root_ancestor.id
|
||||
} }
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
@ -907,11 +935,19 @@ RSpec.shared_examples 'a container registry auth service' do
|
|||
{ 'type' => 'repository',
|
||||
'name' => internal_project.full_path,
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => internal_project.full_path } },
|
||||
'meta' => {
|
||||
'project_path' => internal_project.full_path,
|
||||
'project_id' => internal_project.id,
|
||||
'root_namespace_id' => internal_project.root_ancestor.id
|
||||
} },
|
||||
{ 'type' => 'repository',
|
||||
'name' => public_project.full_path,
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => public_project.full_path } }
|
||||
'meta' => {
|
||||
'project_path' => public_project.full_path,
|
||||
'project_id' => public_project.id,
|
||||
'root_namespace_id' => public_project.root_ancestor.id
|
||||
} }
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
@ -926,7 +962,11 @@ RSpec.shared_examples 'a container registry auth service' do
|
|||
{ 'type' => 'repository',
|
||||
'name' => public_project.full_path,
|
||||
'actions' => ['pull'],
|
||||
'meta' => { 'project_path' => public_project.full_path } }
|
||||
'meta' => {
|
||||
'project_path' => public_project.full_path,
|
||||
'project_id' => public_project.id,
|
||||
'root_namespace_id' => public_project.root_ancestor.id
|
||||
} }
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue