Skip to content

Commit 09f6ce9

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent 09a4690 commit 09f6ce9

File tree

126 files changed

+1426
-505
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+1426
-505
lines changed

.gitlab-ci.yml

+1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ default:
4848
ADD_SLOW_TEST_NOTE_TO_MERGE_REQUEST: "true"
4949
FF_NETWORK_PER_BUILD: "true"
5050
FF_TIMESTAMPS: "true"
51+
FF_USE_FASTZIP: "true"
5152

5253
.if-merge-request-security-canonical-sync: &if-merge-request-security-canonical-sync
5354
if: '$CI_MERGE_REQUEST_SOURCE_PROJECT_PATH == "gitlab-org/security/gitlab" && $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME == $CI_DEFAULT_BRANCH && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'

.gitlab/issue_templates/Documentation.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
Note: Doc work as part of feature development is covered in the Feature Request template.
55
66
* For issues related to features of the docs.gitlab.com site, see
7-
https://gitlab.com/gitlab-org/gitlab-docs/issues/
7+
https://gitlab.com/gitlab-org/technical-writing/docs-gitlab-com/-/issues
88
99
* For information about documentation content and process, see
10-
https://docs.gitlab.com/ee/development/documentation/
10+
https://docs.gitlab.com/development/documentation/
1111
-->
1212

1313
- [ ] Start this issue's title with `Docs:` or `Docs feedback:`.

.gitlab/issue_templates/Security developer workflow.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ After your merge request has been approved according to our [approval guidelines
3434
- You can use the script `bin/secpick` instead of the following steps, to help you cherry-picking. See the [secpick documentation]
3535
- [ ] Create each MR targeting the stable branch `X-Y-stable`, using the [Security merge request template].
3636
- Every merge request will have its own set of to-dos, so make sure to complete those.
37-
- [ ] On the `Related merge requests` section, ensure that **ONLY** `4` merge requests are associated: **ONLY** one targeting `master` and the `3` backports.
38-
- [ ] If there are more associated MRs, re-create another security issue and ensure there are only 4 merge requests associated with that one.
37+
- [ ] On the `Related merge requests` section, ensure that **ONLY** `4` merge requests matching these conditions:
38+
- From the security namespace (`gitlab-org/security`)
39+
- Status is not `Closed`
40+
- (Other MRs not matching these above conditions are acceptable)
41+
- [ ] Among these `4` MRs, one targeting `master` and the `3` backports targeting stable branches.
42+
- [ ] If there are more associated MRs, re-create another security issue and ensure there are only 4 merge requests associated with that one.
3943
- [ ] If this issue requires less than `4` merge requests, add the ~"reduced backports" label.
4044

4145
## Assigning to a release

.rubocop_todo/rspec/spec_file_path_format.yml

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ RSpec/SpecFilePathFormat:
5353
- 'spec/services/ci/create_pipeline_service/rules_spec.rb'
5454
- 'spec/services/ci/create_pipeline_service/run_spec.rb'
5555
- 'spec/services/ci/create_pipeline_service/scripts_spec.rb'
56+
- 'spec/services/ci/create_pipeline_service/stop_linting_spec.rb'
5657
- 'spec/services/ci/create_pipeline_service/tags_spec.rb'
5758
- 'spec/services/ci/create_pipeline_service/variables_spec.rb'
5859
- 'spec/services/ci/create_pipeline_service/workflow_auto_cancel_spec.rb'
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<script>
2-
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
2+
import { GlAlert, GlButton, GlIntersectionObserver } from '@gitlab/ui';
33
import { __, sprintf } from '~/locale';
44
import { renderMarkdown } from '~/notes/utils';
55
import SafeHtml from '~/vue_shared/directives/safe_html';
66
import { sha256 } from '~/lib/utils/text_utility';
77
import { InternalEvents } from '~/tracking';
8-
import { executeAndPresentQuery } from '../../core';
8+
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
9+
import { executeAndPresentQuery, presentPreview } from '../../core';
910
import Counter from '../../utils/counter';
1011
1112
const MAX_GLQL_BLOCKS = 20;
@@ -14,12 +15,13 @@ export default {
1415
name: 'GlqlFacade',
1516
components: {
1617
GlAlert,
17-
GlLoadingIcon,
18+
GlButton,
19+
GlIntersectionObserver,
1820
},
1921
directives: {
2022
SafeHtml,
2123
},
22-
mixins: [InternalEvents.mixin()],
24+
mixins: [InternalEvents.mixin(), glFeatureFlagsMixin()],
2325
props: {
2426
query: {
2527
required: true,
@@ -28,8 +30,10 @@ export default {
2830
},
2931
data() {
3032
return {
33+
loadOnClick: true,
34+
35+
presenterPreview: null,
3136
presenterComponent: null,
32-
loading: false,
3337
error: {
3438
title: null,
3539
message: null,
@@ -41,37 +45,56 @@ export default {
4145
};
4246
},
4347
async mounted() {
44-
if (this.checkGlqlBlocks()) {
45-
this.presentQuery();
46-
}
48+
this.loadOnClick = this.glFeatures.glqlLoadOnClick;
4749
},
4850
methods: {
49-
setLoading(loading) {
50-
this.$emit(loading ? 'loading' : 'loaded');
51-
this.loading = loading;
52-
},
53-
checkGlqlBlocks() {
54-
try {
55-
this.$options.numGlqlBlocks.increment();
56-
return true;
57-
} catch (e) {
58-
this.handleLimitError();
59-
return false;
51+
loadGlqlBlock() {
52+
if (this.presenterComponent || this.presenterPreview) return;
53+
54+
if (this.glFeatures.glqlLoadOnClick || this.checkGlqlBlocksCount()) {
55+
this.presentPreview();
56+
this.loadPresenterComponent();
6057
}
6158
},
62-
async presentQuery() {
59+
60+
reloadGlqlBlock() {
61+
this.presenterComponent = null;
62+
this.presenterPreview = null;
63+
6364
this.dismissAlert();
64-
this.setLoading(true);
65+
this.presentPreview();
66+
this.loadPresenterComponent();
67+
},
6568
69+
async loadPresenterComponent() {
6670
try {
6771
this.presenterComponent = await executeAndPresentQuery(this.query);
6872
this.trackRender();
6973
} catch (error) {
7074
this.handleQueryError(error.message);
71-
} finally {
72-
this.setLoading(false);
7375
}
7476
},
77+
78+
async presentPreview() {
79+
this.dismissAlert();
80+
81+
try {
82+
this.presenterPreview = await presentPreview(this.query);
83+
} catch (error) {
84+
this.handleQueryError(error.message);
85+
}
86+
},
87+
88+
checkGlqlBlocksCount() {
89+
try {
90+
this.$options.numGlqlBlocks.increment();
91+
return true;
92+
} catch (e) {
93+
this.handleLimitError();
94+
return false;
95+
}
96+
},
97+
7598
handleQueryError(message) {
7699
this.error = { ...this.$options.i18n.glqlDisplayError, message };
77100
},
@@ -93,47 +116,53 @@ export default {
93116
safeHtmlConfig: { ALLOWED_TAGS: ['code'] },
94117
i18n: {
95118
glqlDisplayError: {
96-
title: __('An error occurred when trying to display this GLQL block:'),
119+
title: __('An error occurred when trying to display this GLQL view:'),
97120
},
98121
glqlLimitError: {
99122
title: sprintf(
100123
__(
101-
'Only %{n} GLQL blocks can be automatically displayed on a page. Click the button below to manually display this block.',
124+
'Only %{n} GLQL views can be automatically displayed on a page. Click the button below to manually display this block.',
102125
),
103126
{ n: MAX_GLQL_BLOCKS },
104127
),
105128
action: __('Display block'),
106129
},
130+
loadGlqlView: __('Load GLQL view'),
107131
},
108132
numGlqlBlocks: new Counter(MAX_GLQL_BLOCKS),
109133
};
110134
</script>
111135
<template>
112136
<div data-testid="glql-facade">
113-
<gl-alert
114-
v-if="error.title || error.message"
115-
variant="warning"
116-
class="gl-mb-3"
117-
:primary-button-text="error.action"
118-
@dismiss="dismissAlert"
119-
@primaryAction="presentQuery"
120-
>
121-
{{ error.title }}
122-
<ul v-if="error.message" class="!gl-mb-0">
123-
<li v-safe-html:[$options.safeHtmlConfig]="renderMarkdown(error.message)"></li>
124-
</ul>
125-
</gl-alert>
137+
<template v-if="error.title || error.message">
138+
<gl-alert
139+
variant="warning"
140+
class="gl-mb-3"
141+
:primary-button-text="error.action"
142+
@dismiss="dismissAlert"
143+
@primaryAction="reloadGlqlBlock"
144+
>
145+
{{ error.title }}
146+
<ul v-if="error.message" class="!gl-mb-0">
147+
<li v-safe-html:[$options.safeHtmlConfig]="renderMarkdown(error.message)"></li>
148+
</ul>
149+
</gl-alert>
150+
</template>
126151

127-
<component :is="presenterComponent" v-if="presenterComponent" />
128-
<div v-else class="markdown-code-block gl-relative">
129-
<gl-loading-icon
130-
v-if="loading"
131-
size="lg"
132-
class="gl-absolute gl-left-1/2 gl-top-1/2 gl-z-2 -gl-translate-x-1/2 -gl-translate-y-1/2"
133-
/>
134-
<pre
135-
:class="preClasses"
136-
><code :class="{ 'gl-opacity-5': loading }">{{ query.trim() }}</code></pre>
152+
<div v-if="loadOnClick" class="markdown-code-block gl-relative">
153+
<pre :class="preClasses"><gl-button
154+
class="gl-font-regular gl-absolute gl-z-1 gl-top-2/4 gl-left-2/4"
155+
style="transform: translate(-50%, -50%)"
156+
:aria-label="$options.i18n.loadGlqlView"
157+
@click="loadOnClick = false"
158+
>{{ $options.i18n.loadGlqlView }}</gl-button><code class="gl-opacity-2">{{ query.trim() }}</code></pre>
137159
</div>
160+
<gl-intersection-observer v-else @appear="loadGlqlBlock">
161+
<component :is="presenterComponent" v-if="presenterComponent" />
162+
<component :is="presenterPreview" v-else-if="presenterPreview" />
163+
<div v-else class="markdown-code-block gl-relative">
164+
<pre :class="preClasses"><code>{{ query.trim() }}</code></pre>
165+
</div>
166+
</gl-intersection-observer>
138167
</div>
139168
</template>

app/assets/javascripts/glql/components/presenters/list.vue

+26-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script>
2-
import { GlIcon, GlIntersperse, GlLink, GlSprintf } from '@gitlab/ui';
2+
import { GlIcon, GlIntersperse, GlLink, GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
33
import { helpPagePath } from '~/helpers/help_page_helper';
44
import { __ } from '~/locale';
55
@@ -10,6 +10,7 @@ export default {
1010
GlIntersperse,
1111
GlLink,
1212
GlSprintf,
13+
GlSkeletonLoader,
1314
},
1415
inject: ['presenter'],
1516
props: {
@@ -29,6 +30,11 @@ export default {
2930
default: 'ul',
3031
validator: (value) => ['ul', 'ol'].includes(value),
3132
},
33+
isPreview: {
34+
required: false,
35+
type: Boolean,
36+
default: false,
37+
},
3238
},
3339
computed: {
3440
items() {
@@ -49,18 +55,25 @@ export default {
4955
<template>
5056
<div class="gl-mb-4">
5157
<component :is="listType" class="!gl-mb-1" data-testid="list">
52-
<li
53-
v-for="(item, itemIndex) in items"
54-
:key="itemIndex"
55-
:data-testid="`list-item-${itemIndex}`"
56-
>
57-
<gl-intersperse separator=" · ">
58-
<span v-for="field in fields" :key="field.key">
59-
<component :is="presenter.forField(item, field.key)" />
60-
</span>
61-
</gl-intersperse>
62-
</li>
63-
<div v-if="!items.length" :dismissible="false" variant="tip" class="!gl-my-2">
58+
<template v-if="isPreview">
59+
<li v-for="i in 5" :key="i">
60+
<gl-skeleton-loader :width="400" :lines="1" />
61+
</li>
62+
</template>
63+
<template v-else-if="items.length">
64+
<li
65+
v-for="(item, itemIndex) in items"
66+
:key="itemIndex"
67+
:data-testid="`list-item-${itemIndex}`"
68+
>
69+
<gl-intersperse separator=" · ">
70+
<span v-for="field in fields" :key="field.key">
71+
<component :is="presenter.forField(item, field.key)" />
72+
</span>
73+
</gl-intersperse>
74+
</li>
75+
</template>
76+
<div v-else-if="!items.length" :dismissible="false" variant="tip" class="!gl-my-2">
6477
{{ __('No data found for this query') }}
6578
</div>
6679
</component>

app/assets/javascripts/glql/components/presenters/table.vue

+26-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script>
2-
import { GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
2+
import { GlIcon, GlLink, GlSprintf, GlSkeletonLoader } from '@gitlab/ui';
33
import { helpPagePath } from '~/helpers/help_page_helper';
44
import { __ } from '~/locale';
55
import Sorter from '../../core/sorter';
@@ -11,6 +11,7 @@ export default {
1111
GlIcon,
1212
GlLink,
1313
GlSprintf,
14+
GlSkeletonLoader,
1415
ThResizable,
1516
},
1617
inject: ['presenter'],
@@ -25,6 +26,11 @@ export default {
2526
type: Object,
2627
validator: ({ fields }) => Array.isArray(fields) && fields.length > 0,
2728
},
29+
isPreview: {
30+
required: false,
31+
type: Boolean,
32+
default: false,
33+
},
2834
},
2935
data() {
3036
const items = this.data.nodes.slice();
@@ -73,16 +79,25 @@ export default {
7379
</tr>
7480
</thead>
7581
<tbody>
76-
<tr
77-
v-for="(item, itemIndex) in items"
78-
:key="item.id"
79-
:data-testid="`table-row-${itemIndex}`"
80-
>
81-
<td v-for="field in fields" :key="field.key">
82-
<component :is="presenter.forField(item, field.key)" />
83-
</td>
84-
</tr>
85-
<tr v-if="!items.length">
82+
<template v-if="isPreview">
83+
<tr v-for="i in 5" :key="i">
84+
<td v-for="field in fields" :key="field.key">
85+
<gl-skeleton-loader :width="120" :lines="1" />
86+
</td>
87+
</tr>
88+
</template>
89+
<template v-else-if="items.length">
90+
<tr
91+
v-for="(item, itemIndex) in items"
92+
:key="item.id"
93+
:data-testid="`table-row-${itemIndex}`"
94+
>
95+
<td v-for="field in fields" :key="field.key">
96+
<component :is="presenter.forField(item, field.key)" />
97+
</td>
98+
</tr>
99+
</template>
100+
<tr v-else-if="!items.length">
86101
<td :colspan="fields.length" class="gl-text-center">
87102
{{ __('No data found for this query') }}
88103
</td>

0 commit comments

Comments
 (0)