Skip to content

Commit

Permalink
Add latest changes from gitlab-org/gitlab@master
Browse files Browse the repository at this point in the history
  • Loading branch information
GitLab Bot committed Jul 13, 2022
1 parent 58f103b commit 33a43bd
Show file tree
Hide file tree
Showing 68 changed files with 849 additions and 155 deletions.
2 changes: 1 addition & 1 deletion .nvmrc
@@ -1 +1 @@
16.14.0
16.15.0
2 changes: 1 addition & 1 deletion GITLAB_KAS_VERSION
@@ -1 +1 @@
15.1.0
15.2.0
2 changes: 1 addition & 1 deletion Gemfile
Expand Up @@ -93,7 +93,7 @@ gem 'gpgme', '~> 2.0.19'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
# see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master
gem 'gitlab_omniauth-ldap', '~> 2.1.1', require: 'omniauth-ldap'
gem 'gitlab_omniauth-ldap', '~> 2.2.0', require: 'omniauth-ldap'
gem 'net-ldap', '~> 0.16.3'

# API
Expand Down
8 changes: 4 additions & 4 deletions Gemfile.lock
Expand Up @@ -549,9 +549,9 @@ GEM
rubocop-rspec (~> 1.44)
gitlab_chronic_duration (0.10.6.2)
numerizer (~> 0.2)
gitlab_omniauth-ldap (2.1.1)
gitlab_omniauth-ldap (2.2.0)
net-ldap (~> 0.16)
omniauth (~> 1.3)
omniauth (>= 1.3, < 3)
pyu-ruby-sasl (>= 0.0.3.3, < 0.1)
rubyntlm (~> 0.5)
globalid (1.0.0)
Expand Down Expand Up @@ -1197,7 +1197,7 @@ GEM
ruby2_keywords (0.0.5)
ruby_parser (3.15.0)
sexp_processor (~> 4.9)
rubyntlm (0.6.2)
rubyntlm (0.6.3)
rubypants (0.2.0)
rubyzip (2.3.2)
rugged (1.2.0)
Expand Down Expand Up @@ -1573,7 +1573,7 @@ DEPENDENCIES
gitlab-sidekiq-fetcher (= 0.8.0)
gitlab-styles (~> 7.1.0)
gitlab_chronic_duration (~> 0.10.6.2)
gitlab_omniauth-ldap (~> 2.1.1)
gitlab_omniauth-ldap (~> 2.2.0)
gon (~> 6.4.0)
google-api-client (~> 0.33)
google-protobuf (~> 3.19.0)
Expand Down
@@ -0,0 +1,9 @@
#import "../fragments/user.fragment.graphql"

query getUsersByUsernames($usernames: [String!]) {
users(usernames: $usernames) {
nodes {
...User
}
}
}
@@ -0,0 +1,9 @@
#import "../fragments/user.fragment.graphql"

query searchAllUsers($search: String!, $first: Int = null) {
users(search: $search, first: $first) {
nodes {
...User
}
}
}
Expand Up @@ -84,7 +84,7 @@ export default {
<gl-icon
v-if="hasState"
ref="iconElementXL"
class="mr-2 d-block"
class="gl-mr-3"
:class="iconClasses"
:name="iconName"
:title="stateTitle"
Expand Down
@@ -0,0 +1,14 @@
import { s__ } from '~/locale';

export const timelineTabI18n = Object.freeze({
title: s__('Incident|Timeline'),
emptyDescription: s__('Incident|No timeline items have been added yet.'),
addEventButton: s__('Incident|Add new timeline event'),
});

export const timelineFormI18n = Object.freeze({
createError: s__('Incident|Error creating incident timeline event: %{error}'),
areaPlaceholder: s__('Incident|Timeline text...'),
saveAndAdd: s__('Incident|Save and add another event'),
areaLabel: s__('Incident|Timeline text'),
});
@@ -0,0 +1,13 @@
mutation CreateTimelineEvent($input: TimelineEventCreateInput!) {
timelineEventCreate(input: $input) {
timelineEvent {
id
note
noteHtml
action
occurredAt
createdAt
}
errors
}
}
Expand Up @@ -4,17 +4,11 @@ query GetTimelineEvents($fullPath: ID!, $incidentId: IssueID!) {
incidentManagementTimelineEvents(incidentId: $incidentId) {
nodes {
id
author {
id
name
username
}
note
noteHtml
action
occurredAt
createdAt
updatedAt
}
}
}
Expand Down
@@ -0,0 +1,252 @@
<script>
import { GlDatepicker, GlFormInput, GlFormGroup, GlButton, GlIcon } from '@gitlab/ui';
import { produce } from 'immer';
import { sortBy } from 'lodash';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPE_ISSUE } from '~/graphql_shared/constants';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
import { createAlert } from '~/flash';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
import { sprintf } from '~/locale';
import { displayAndLogError, getUtcShiftedDateNow } from './utils';
import { timelineFormI18n } from './constants';
import CreateTimelineEvent from './graphql/queries/create_timeline_event.mutation.graphql';
import getTimelineEvents from './graphql/queries/get_timeline_events.query.graphql';
export default {
name: 'IncidentTimelineEventForm',
restrictedToolBarItems: [
'quote',
'strikethrough',
'bullet-list',
'numbered-list',
'task-list',
'collapsible-section',
'table',
'full-screen',
],
components: {
MarkdownField,
GlDatepicker,
GlFormInput,
GlFormGroup,
GlButton,
GlIcon,
},
i18n: timelineFormI18n,
directives: {
autofocusonshow,
},
inject: ['fullPath', 'issuableId'],
props: {
hasTimelineEvents: {
type: Boolean,
required: true,
},
},
data() {
// Create shifted date to force the datepicker to format in UTC
const utcShiftedDate = getUtcShiftedDateNow();
return {
currentDate: utcShiftedDate,
currentHour: utcShiftedDate.getHours(),
currentMinute: utcShiftedDate.getMinutes(),
timelineText: '',
createTimelineEventActive: false,
datepickerTextInput: null,
};
},
methods: {
hideIncidentTimelineEventForm() {
this.$emit('hide-incident-timeline-event-form');
},
focusDate() {
this.$refs.datepicker.$el.focus();
},
updateCache(store, { data }) {
const { timelineEvent: event, errors } = data?.timelineEventCreate || {};
if (errors.length) {
return;
}
const variables = {
incidentId: convertToGraphQLId(TYPE_ISSUE, this.issuableId),
fullPath: this.fullPath,
};
const sourceData = store.readQuery({
query: getTimelineEvents,
variables,
});
const newData = produce(sourceData, (draftData) => {
const { nodes: draftEventList } = draftData.project.incidentManagementTimelineEvents;
draftEventList.push(event);
// ISOStrings sort correctly in lexical order
const sortedEvents = sortBy(draftEventList, 'occurredAt');
draftData.project.incidentManagementTimelineEvents.nodes = sortedEvents;
});
store.writeQuery({
query: getTimelineEvents,
variables,
data: newData,
});
},
createIncidentTimelineEvent(addOneEvent) {
this.createTimelineEventActive = true;
return this.$apollo
.mutate({
mutation: CreateTimelineEvent,
variables: {
input: {
incidentId: convertToGraphQLId(TYPE_ISSUE, this.issuableId),
note: this.timelineText,
occurredAt: this.createDateString(),
},
},
update: this.updateCache,
})
.then(({ data = {} }) => {
const errors = data.timelineEventCreate?.errors;
if (errors.length) {
createAlert({
message: sprintf(this.$options.i18n.createError, { error: errors.join('. ') }, false),
});
}
})
.catch(displayAndLogError)
.finally(() => {
this.createTimelineEventActive = false;
this.timelineText = '';
if (addOneEvent) {
this.hideIncidentTimelineEventForm();
}
});
},
createDateString() {
const [years, months, days] = this.datepickerTextInput.split('-');
const utcDate = new Date(
Date.UTC(years, months - 1, days, this.currentHour, this.currentMinute),
);
return utcDate.toISOString();
},
},
};
</script>
<template>
<div
class="gl-relative gl-display-flex gl-align-items-center"
:class="{ 'timeline-entry-vertical-line': hasTimelineEvents }"
>
<div
v-if="hasTimelineEvents"
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"
>
<gl-icon name="comment" class="note-icon" />
</div>
<form class="gl-flex-grow-1" :class="{ 'gl-border-t': hasTimelineEvents }">
<div
class="gl-display-flex gl-flex-direction-column gl-sm-flex-direction-row datetime-picker"
>
<gl-form-group :label="__('Date')" class="gl-mt-3 gl-mr-3">
<gl-datepicker id="incident-date" #default="{ formattedDate }" v-model="currentDate">
<gl-form-input
id="incident-date"
ref="datepicker"
v-model="datepickerTextInput"
class="gl-datepicker-input gl-pr-7!"
:value="formattedDate"
:placeholder="__('YYYY-MM-DD')"
@keydown.enter="onKeydown"
/>
</gl-datepicker>
</gl-form-group>
<div class="gl-display-flex gl-mt-3">
<gl-form-group :label="__('Time')">
<div class="gl-display-flex">
<label label-for="timeline-input-hours" class="sr-only"></label>
<gl-form-input
id="timeline-input-hours"
v-model="currentHour"
data-testid="input-hours"
size="xs"
type="number"
min="00"
max="23"
/>
<label label-for="timeline-input-minutes" class="sr-only"></label>
<gl-form-input
id="timeline-input-minutes"
v-model="currentMinute"
class="gl-ml-3"
data-testid="input-minutes"
size="xs"
type="number"
min="00"
max="59"
/>
</div>
</gl-form-group>
<p class="gl-ml-3 gl-align-self-end gl-line-height-32">{{ __('UTC') }}</p>
</div>
</div>
<div class="common-note-form">
<gl-form-group :label="$options.i18n.areaLabel">
<markdown-field
:can-attach-file="false"
:add-spacing-classes="false"
:show-comment-tool-bar="false"
:textarea-value="timelineText"
:restricted-tool-bar-items="$options.restrictedToolBarItems"
markdown-docs-path=""
class="bordered-box gl-mt-0"
>
<template #textarea>
<textarea
v-model="timelineText"
class="note-textarea js-gfm-input js-autosize markdown-area"
dir="auto"
data-supports-quick-actions="false"
:aria-label="__('Description')"
:placeholder="$options.i18n.areaPlaceholder"
>
</textarea>
</template>
</markdown-field>
</gl-form-group>
</div>
<gl-form-group class="gl-mb-0">
<gl-button
variant="confirm"
category="primary"
class="gl-mr-3"
:loading="createTimelineEventActive"
@click="createIncidentTimelineEvent(true)"
>
{{ __('Save') }}
</gl-button>
<gl-button
variant="confirm"
category="secondary"
class="gl-mr-3 gl-ml-n2"
:loading="createTimelineEventActive"
@click="createIncidentTimelineEvent(false)"
>
{{ $options.i18n.saveAndAdd }}
</gl-button>
<gl-button
class="gl-ml-n2"
:disabled="createTimelineEventActive"
@click="hideIncidentTimelineEventForm"
>
{{ __('Cancel') }}
</gl-button>
<div class="gl-border-b gl-pt-5"></div>
</gl-form-group>
</form>
</div>
</template>

0 comments on commit 33a43bd

Please sign in to comment.