Skip to content

Commit 33a43bd

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent 58f103b commit 33a43bd

File tree

68 files changed

+849
-155
lines changed

Some content is hidden

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

68 files changed

+849
-155
lines changed

.nvmrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
16.14.0
1+
16.15.0

GITLAB_KAS_VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
15.1.0
1+
15.2.0

Gemfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ gem 'gpgme', '~> 2.0.19'
9393
# LDAP Auth
9494
# GitLab fork with several improvements to original library. For full list of changes
9595
# see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master
96-
gem 'gitlab_omniauth-ldap', '~> 2.1.1', require: 'omniauth-ldap'
96+
gem 'gitlab_omniauth-ldap', '~> 2.2.0', require: 'omniauth-ldap'
9797
gem 'net-ldap', '~> 0.16.3'
9898

9999
# API

Gemfile.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -549,9 +549,9 @@ GEM
549549
rubocop-rspec (~> 1.44)
550550
gitlab_chronic_duration (0.10.6.2)
551551
numerizer (~> 0.2)
552-
gitlab_omniauth-ldap (2.1.1)
552+
gitlab_omniauth-ldap (2.2.0)
553553
net-ldap (~> 0.16)
554-
omniauth (~> 1.3)
554+
omniauth (>= 1.3, < 3)
555555
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
556556
rubyntlm (~> 0.5)
557557
globalid (1.0.0)
@@ -1197,7 +1197,7 @@ GEM
11971197
ruby2_keywords (0.0.5)
11981198
ruby_parser (3.15.0)
11991199
sexp_processor (~> 4.9)
1200-
rubyntlm (0.6.2)
1200+
rubyntlm (0.6.3)
12011201
rubypants (0.2.0)
12021202
rubyzip (2.3.2)
12031203
rugged (1.2.0)
@@ -1573,7 +1573,7 @@ DEPENDENCIES
15731573
gitlab-sidekiq-fetcher (= 0.8.0)
15741574
gitlab-styles (~> 7.1.0)
15751575
gitlab_chronic_duration (~> 0.10.6.2)
1576-
gitlab_omniauth-ldap (~> 2.1.1)
1576+
gitlab_omniauth-ldap (~> 2.2.0)
15771577
gon (~> 6.4.0)
15781578
google-api-client (~> 0.33)
15791579
google-protobuf (~> 3.19.0)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#import "../fragments/user.fragment.graphql"
2+
3+
query getUsersByUsernames($usernames: [String!]) {
4+
users(usernames: $usernames) {
5+
nodes {
6+
...User
7+
}
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#import "../fragments/user.fragment.graphql"
2+
3+
query searchAllUsers($search: String!, $first: Int = null) {
4+
users(search: $search, first: $first) {
5+
nodes {
6+
...User
7+
}
8+
}
9+
}

app/assets/javascripts/issuable/components/related_issuable_item.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default {
8484
<gl-icon
8585
v-if="hasState"
8686
ref="iconElementXL"
87-
class="mr-2 d-block"
87+
class="gl-mr-3"
8888
:class="iconClasses"
8989
:name="iconName"
9090
:title="stateTitle"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { s__ } from '~/locale';
2+
3+
export const timelineTabI18n = Object.freeze({
4+
title: s__('Incident|Timeline'),
5+
emptyDescription: s__('Incident|No timeline items have been added yet.'),
6+
addEventButton: s__('Incident|Add new timeline event'),
7+
});
8+
9+
export const timelineFormI18n = Object.freeze({
10+
createError: s__('Incident|Error creating incident timeline event: %{error}'),
11+
areaPlaceholder: s__('Incident|Timeline text...'),
12+
saveAndAdd: s__('Incident|Save and add another event'),
13+
areaLabel: s__('Incident|Timeline text'),
14+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
mutation CreateTimelineEvent($input: TimelineEventCreateInput!) {
2+
timelineEventCreate(input: $input) {
3+
timelineEvent {
4+
id
5+
note
6+
noteHtml
7+
action
8+
occurredAt
9+
createdAt
10+
}
11+
errors
12+
}
13+
}

app/assets/javascripts/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql

-6
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,11 @@ query GetTimelineEvents($fullPath: ID!, $incidentId: IssueID!) {
44
incidentManagementTimelineEvents(incidentId: $incidentId) {
55
nodes {
66
id
7-
author {
8-
id
9-
name
10-
username
11-
}
127
note
138
noteHtml
149
action
1510
occurredAt
1611
createdAt
17-
updatedAt
1812
}
1913
}
2014
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
<script>
2+
import { GlDatepicker, GlFormInput, GlFormGroup, GlButton, GlIcon } from '@gitlab/ui';
3+
import { produce } from 'immer';
4+
import { sortBy } from 'lodash';
5+
import { convertToGraphQLId } from '~/graphql_shared/utils';
6+
import { TYPE_ISSUE } from '~/graphql_shared/constants';
7+
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
8+
import { createAlert } from '~/flash';
9+
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
10+
import { sprintf } from '~/locale';
11+
import { displayAndLogError, getUtcShiftedDateNow } from './utils';
12+
import { timelineFormI18n } from './constants';
13+
14+
import CreateTimelineEvent from './graphql/queries/create_timeline_event.mutation.graphql';
15+
import getTimelineEvents from './graphql/queries/get_timeline_events.query.graphql';
16+
17+
export default {
18+
name: 'IncidentTimelineEventForm',
19+
restrictedToolBarItems: [
20+
'quote',
21+
'strikethrough',
22+
'bullet-list',
23+
'numbered-list',
24+
'task-list',
25+
'collapsible-section',
26+
'table',
27+
'full-screen',
28+
],
29+
components: {
30+
MarkdownField,
31+
GlDatepicker,
32+
GlFormInput,
33+
GlFormGroup,
34+
GlButton,
35+
GlIcon,
36+
},
37+
i18n: timelineFormI18n,
38+
directives: {
39+
autofocusonshow,
40+
},
41+
inject: ['fullPath', 'issuableId'],
42+
props: {
43+
hasTimelineEvents: {
44+
type: Boolean,
45+
required: true,
46+
},
47+
},
48+
data() {
49+
// Create shifted date to force the datepicker to format in UTC
50+
const utcShiftedDate = getUtcShiftedDateNow();
51+
return {
52+
currentDate: utcShiftedDate,
53+
currentHour: utcShiftedDate.getHours(),
54+
currentMinute: utcShiftedDate.getMinutes(),
55+
timelineText: '',
56+
createTimelineEventActive: false,
57+
datepickerTextInput: null,
58+
};
59+
},
60+
methods: {
61+
hideIncidentTimelineEventForm() {
62+
this.$emit('hide-incident-timeline-event-form');
63+
},
64+
focusDate() {
65+
this.$refs.datepicker.$el.focus();
66+
},
67+
updateCache(store, { data }) {
68+
const { timelineEvent: event, errors } = data?.timelineEventCreate || {};
69+
70+
if (errors.length) {
71+
return;
72+
}
73+
74+
const variables = {
75+
incidentId: convertToGraphQLId(TYPE_ISSUE, this.issuableId),
76+
fullPath: this.fullPath,
77+
};
78+
79+
const sourceData = store.readQuery({
80+
query: getTimelineEvents,
81+
variables,
82+
});
83+
84+
const newData = produce(sourceData, (draftData) => {
85+
const { nodes: draftEventList } = draftData.project.incidentManagementTimelineEvents;
86+
draftEventList.push(event);
87+
// ISOStrings sort correctly in lexical order
88+
const sortedEvents = sortBy(draftEventList, 'occurredAt');
89+
draftData.project.incidentManagementTimelineEvents.nodes = sortedEvents;
90+
});
91+
92+
store.writeQuery({
93+
query: getTimelineEvents,
94+
variables,
95+
data: newData,
96+
});
97+
},
98+
createIncidentTimelineEvent(addOneEvent) {
99+
this.createTimelineEventActive = true;
100+
return this.$apollo
101+
.mutate({
102+
mutation: CreateTimelineEvent,
103+
variables: {
104+
input: {
105+
incidentId: convertToGraphQLId(TYPE_ISSUE, this.issuableId),
106+
note: this.timelineText,
107+
occurredAt: this.createDateString(),
108+
},
109+
},
110+
update: this.updateCache,
111+
})
112+
.then(({ data = {} }) => {
113+
const errors = data.timelineEventCreate?.errors;
114+
if (errors.length) {
115+
createAlert({
116+
message: sprintf(this.$options.i18n.createError, { error: errors.join('. ') }, false),
117+
});
118+
}
119+
})
120+
.catch(displayAndLogError)
121+
.finally(() => {
122+
this.createTimelineEventActive = false;
123+
this.timelineText = '';
124+
if (addOneEvent) {
125+
this.hideIncidentTimelineEventForm();
126+
}
127+
});
128+
},
129+
createDateString() {
130+
const [years, months, days] = this.datepickerTextInput.split('-');
131+
const utcDate = new Date(
132+
Date.UTC(years, months - 1, days, this.currentHour, this.currentMinute),
133+
);
134+
return utcDate.toISOString();
135+
},
136+
},
137+
};
138+
</script>
139+
140+
<template>
141+
<div
142+
class="gl-relative gl-display-flex gl-align-items-center"
143+
:class="{ 'timeline-entry-vertical-line': hasTimelineEvents }"
144+
>
145+
<div
146+
v-if="hasTimelineEvents"
147+
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-align-self-start gl-bg-white gl-text-gray-200 gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-full gl-mt-2 gl-mr-3 gl-w-8 gl-h-8 gl-z-index-1"
148+
>
149+
<gl-icon name="comment" class="note-icon" />
150+
</div>
151+
<form class="gl-flex-grow-1" :class="{ 'gl-border-t': hasTimelineEvents }">
152+
<div
153+
class="gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row datetime-picker"
154+
>
155+
<gl-form-group :label="__('Date')" class="gl-mt-3 gl-mr-3">
156+
<gl-datepicker id="incident-date" #default="{ formattedDate }" v-model="currentDate">
157+
<gl-form-input
158+
id="incident-date"
159+
ref="datepicker"
160+
v-model="datepickerTextInput"
161+
class="gl-datepicker-input gl-pr-7!"
162+
:value="formattedDate"
163+
:placeholder="__('YYYY-MM-DD')"
164+
@keydown.enter="onKeydown"
165+
/>
166+
</gl-datepicker>
167+
</gl-form-group>
168+
<div class="gl-display-flex gl-mt-3">
169+
<gl-form-group :label="__('Time')">
170+
<div class="gl-display-flex">
171+
<label label-for="timeline-input-hours" class="sr-only"></label>
172+
<gl-form-input
173+
id="timeline-input-hours"
174+
v-model="currentHour"
175+
data-testid="input-hours"
176+
size="xs"
177+
type="number"
178+
min="00"
179+
max="23"
180+
/>
181+
<label label-for="timeline-input-minutes" class="sr-only"></label>
182+
<gl-form-input
183+
id="timeline-input-minutes"
184+
v-model="currentMinute"
185+
class="gl-ml-3"
186+
data-testid="input-minutes"
187+
size="xs"
188+
type="number"
189+
min="00"
190+
max="59"
191+
/>
192+
</div>
193+
</gl-form-group>
194+
<p class="gl-ml-3 gl-align-self-end gl-line-height-32">{{ __('UTC') }}</p>
195+
</div>
196+
</div>
197+
<div class="common-note-form">
198+
<gl-form-group :label="$options.i18n.areaLabel">
199+
<markdown-field
200+
:can-attach-file="false"
201+
:add-spacing-classes="false"
202+
:show-comment-tool-bar="false"
203+
:textarea-value="timelineText"
204+
:restricted-tool-bar-items="$options.restrictedToolBarItems"
205+
markdown-docs-path=""
206+
class="bordered-box gl-mt-0"
207+
>
208+
<template #textarea>
209+
<textarea
210+
v-model="timelineText"
211+
class="note-textarea js-gfm-input js-autosize markdown-area"
212+
dir="auto"
213+
data-supports-quick-actions="false"
214+
:aria-label="__('Description')"
215+
:placeholder="$options.i18n.areaPlaceholder"
216+
>
217+
</textarea>
218+
</template>
219+
</markdown-field>
220+
</gl-form-group>
221+
</div>
222+
<gl-form-group class="gl-mb-0">
223+
<gl-button
224+
variant="confirm"
225+
category="primary"
226+
class="gl-mr-3"
227+
:loading="createTimelineEventActive"
228+
@click="createIncidentTimelineEvent(true)"
229+
>
230+
{{ __('Save') }}
231+
</gl-button>
232+
<gl-button
233+
variant="confirm"
234+
category="secondary"
235+
class="gl-mr-3 gl-ml-n2"
236+
:loading="createTimelineEventActive"
237+
@click="createIncidentTimelineEvent(false)"
238+
>
239+
{{ $options.i18n.saveAndAdd }}
240+
</gl-button>
241+
<gl-button
242+
class="gl-ml-n2"
243+
:disabled="createTimelineEventActive"
244+
@click="hideIncidentTimelineEventForm"
245+
>
246+
{{ __('Cancel') }}
247+
</gl-button>
248+
<div class="gl-border-b gl-pt-5"></div>
249+
</gl-form-group>
250+
</form>
251+
</div>
252+
</template>

0 commit comments

Comments
 (0)