diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-31 06:10:18 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-10-31 06:10:18 +0300 |
commit | b6cb3bc944b0ca803e758d9e9da3790c0f310d21 (patch) | |
tree | a0712bd4d614880aa1d3f724e39308f3fa7c4e2a | |
parent | 453bb35fc81741c1dd7178cde1f64df2c9ec7252 (diff) |
Add latest changes from gitlab-org/gitlab@master
24 files changed, 245 insertions, 333 deletions
diff --git a/app/assets/javascripts/content_editor/components/suggestions_dropdown.vue b/app/assets/javascripts/content_editor/components/suggestions_dropdown.vue index 6535d9eaa5d..b34ebe85eb4 100644 --- a/app/assets/javascripts/content_editor/components/suggestions_dropdown.vue +++ b/app/assets/javascripts/content_editor/components/suggestions_dropdown.vue @@ -161,6 +161,8 @@ export default { }, onKeyDown({ event }) { + if (!this.items.length) return false; + if (event.key === 'ArrowUp') { this.upHandler(); return true; diff --git a/app/assets/javascripts/content_editor/extensions/suggestions.js b/app/assets/javascripts/content_editor/extensions/suggestions.js index 0560322191e..f7ff2fd6647 100644 --- a/app/assets/javascripts/content_editor/extensions/suggestions.js +++ b/app/assets/javascripts/content_editor/extensions/suggestions.js @@ -57,6 +57,7 @@ function createSuggestionPlugin({ render: () => { let component; let popup; + let isHidden = false; const onUpdate = (props) => { component?.updateProps({ ...props, loading: false }); @@ -88,6 +89,12 @@ function createSuggestionPlugin({ popup = tippy('body', { getReferenceClientRect: props.clientRect, appendTo: () => document.body, + onHide: () => { + isHidden = true; + }, + onShow: () => { + isHidden = false; + }, content: component.element, showOnCreate: true, interactive: true, @@ -100,6 +107,8 @@ function createSuggestionPlugin({ onUpdate, onKeyDown(props) { + if (isHidden) return false; + if (props.event.key === 'Escape') { popup?.[0].hide(); diff --git a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue index c7d8a50f402..62e1ebc50a8 100644 --- a/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue +++ b/app/assets/javascripts/work_items/components/notes/work_item_comment_form.vue @@ -195,7 +195,6 @@ export default { :autocomplete-data-sources="autocompleteDataSources" :form-field-props="formFieldProps" :add-spacing-classes="false" - data-testid="work-item-add-comment" use-bottom-toolbar supports-quick-actions :autofocus="autofocus" diff --git a/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue b/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue index 2d36a89169a..cb9a560f9e1 100644 --- a/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue +++ b/app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue @@ -207,7 +207,6 @@ export default { <gl-button v-if="showEdit" v-gl-tooltip - data-testid="edit-work-item-note" data-track-action="click_button" data-track-label="edit_button" category="tertiary" @@ -219,7 +218,6 @@ export default { <gl-disclosure-dropdown ref="dropdown" v-gl-tooltip - data-testid="work-item-note-actions" icon="ellipsis_v" text-sr-only placement="right" diff --git a/app/assets/javascripts/work_items/components/work_item_actions.vue b/app/assets/javascripts/work_items/components/work_item_actions.vue index 08ad03ad4fe..88f82fb6fb7 100644 --- a/app/assets/javascripts/work_items/components/work_item_actions.vue +++ b/app/assets/javascripts/work_items/components/work_item_actions.vue @@ -20,7 +20,6 @@ import { I18N_WORK_ITEM_DELETE, I18N_WORK_ITEM_ARE_YOU_SURE_DELETE, TEST_ID_CONFIDENTIALITY_TOGGLE_ACTION, - TEST_ID_NOTIFICATIONS_TOGGLE_ACTION, TEST_ID_NOTIFICATIONS_TOGGLE_FORM, TEST_ID_DELETE_ACTION, TEST_ID_PROMOTE_ACTION, @@ -39,8 +38,8 @@ import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query. export default { i18n: { - enableTaskConfidentiality: s__('WorkItem|Turn on confidentiality'), - disableTaskConfidentiality: s__('WorkItem|Turn off confidentiality'), + enableConfidentiality: s__('WorkItem|Turn on confidentiality'), + disableConfidentiality: s__('WorkItem|Turn off confidentiality'), notifications: s__('WorkItem|Notifications'), notificationOn: s__('WorkItem|Notifications turned on.'), notificationOff: s__('WorkItem|Notifications turned off.'), @@ -60,7 +59,6 @@ export default { }, mixins: [Tracking.mixin({ label: 'actions_menu' })], isLoggedIn: isLoggedIn(), - notificationsToggleTestId: TEST_ID_NOTIFICATIONS_TOGGLE_ACTION, notificationsToggleFormTestId: TEST_ID_NOTIFICATIONS_TOGGLE_FORM, confidentialityTestId: TEST_ID_CONFIDENTIALITY_TOGGLE_ACTION, copyReferenceTestId: TEST_ID_COPY_REFERENCE_ACTION, @@ -165,6 +163,11 @@ export default { canPromoteToObjective() { return this.canUpdate && this.workItemType === WORK_ITEM_TYPE_VALUE_KEY_RESULT; }, + confidentialItemText() { + return this.isConfidential + ? this.$options.i18n.disableConfidentiality + : this.$options.i18n.enableConfidentiality; + }, objectiveWorkItemTypeId() { return this.workItemTypes.find((type) => type.name === WORK_ITEM_TYPE_VALUE_OBJECTIVE).id; }, @@ -267,7 +270,7 @@ export default { icon="ellipsis_v" data-testid="work-item-actions-dropdown" text-sr-only - :text="__('More actions')" + :toggle-text="__('More actions')" category="tertiary" :auto-close="false" no-caret @@ -282,7 +285,6 @@ export default { <gl-toggle :value="subscribedToNotifications" :label="$options.i18n.notifications" - :data-testid="$options.notificationsToggleTestId" class="work-item-notification-toggle" label-position="left" @change="toggleNotifications($event)" @@ -299,49 +301,46 @@ export default { > <template #list-item>{{ __('Promote to objective') }}</template> </gl-disclosure-dropdown-item> - <template v-if="canUpdate && !isParentConfidential"> - <gl-disclosure-dropdown-item - :data-testid="$options.confidentialityTestId" - @action="handleToggleWorkItemConfidentiality" - ><template #list-item>{{ - isConfidential - ? $options.i18n.disableTaskConfidentiality - : $options.i18n.enableTaskConfidentiality - }}</template></gl-disclosure-dropdown-item - > - </template> + + <gl-disclosure-dropdown-item + v-if="canUpdate && !isParentConfidential" + :data-testid="$options.confidentialityTestId" + @action="handleToggleWorkItemConfidentiality" + > + <template #list-item>{{ confidentialItemText }}</template> + </gl-disclosure-dropdown-item> + <gl-disclosure-dropdown-item - ref="workItemReference" :data-testid="$options.copyReferenceTestId" :data-clipboard-text="workItemReference" @action="copyToClipboard(workItemReference, $options.i18n.referenceCopied)" - ><template #list-item>{{ - $options.i18n.copyReference - }}</template></gl-disclosure-dropdown-item > - <template v-if="$options.isLoggedIn && workItemCreateNoteEmail"> - <gl-disclosure-dropdown-item - ref="workItemCreateNoteEmail" - :data-testid="$options.copyCreateNoteEmailTestId" - :data-clipboard-text="workItemCreateNoteEmail" - @action="copyToClipboard(workItemCreateNoteEmail, $options.i18n.emailAddressCopied)" - ><template #list-item>{{ - i18n.copyCreateNoteEmail - }}</template></gl-disclosure-dropdown-item - > - </template> - <gl-dropdown-divider v-if="canDelete" /> + <template #list-item>{{ $options.i18n.copyReference }}</template> + </gl-disclosure-dropdown-item> + <gl-disclosure-dropdown-item - v-if="canDelete" - :data-testid="$options.deleteActionTestId" - variant="danger" - @action="handleDelete" + v-if="$options.isLoggedIn && workItemCreateNoteEmail" + :data-testid="$options.copyCreateNoteEmailTestId" + :data-clipboard-text="workItemCreateNoteEmail" + @action="copyToClipboard(workItemCreateNoteEmail, $options.i18n.emailAddressCopied)" > - <template #list-item - ><span class="text-danger">{{ i18n.deleteWorkItem }}</span></template - > + <template #list-item>{{ i18n.copyCreateNoteEmail }}</template> </gl-disclosure-dropdown-item> + + <template v-if="canDelete"> + <gl-dropdown-divider /> + <gl-disclosure-dropdown-item + :data-testid="$options.deleteActionTestId" + variant="danger" + @action="handleDelete" + > + <template #list-item> + <span class="text-danger">{{ i18n.deleteWorkItem }}</span> + </template> + </gl-disclosure-dropdown-item> + </template> </gl-disclosure-dropdown> + <gl-modal ref="modal" modal-id="work-item-confirm-delete" diff --git a/app/assets/javascripts/work_items/components/work_item_award_emoji.vue b/app/assets/javascripts/work_items/components/work_item_award_emoji.vue index fb710836a88..f806946509f 100644 --- a/app/assets/javascripts/work_items/components/work_item_award_emoji.vue +++ b/app/assets/javascripts/work_items/components/work_item_award_emoji.vue @@ -238,7 +238,6 @@ export default { <template> <div v-if="!isLoading" class="gl-mt-3"> <awards-list - data-testid="work-item-award-list" :awards="awards" :can-award-emoji="$options.isLoggedIn" :current-user-id="currentUserId" diff --git a/app/assets/javascripts/work_items/components/work_item_description.vue b/app/assets/javascripts/work_items/components/work_item_description.vue index 245099d958d..77c573b47e4 100644 --- a/app/assets/javascripts/work_items/components/work_item_description.vue +++ b/app/assets/javascripts/work_items/components/work_item_description.vue @@ -244,13 +244,7 @@ export default { @keydown.ctrl.enter="updateWorkItem" /> <div class="gl-display-flex"> - <gl-alert - v-if="hasConflicts" - :dismissible="false" - variant="danger" - class="gl-w-full" - data-testid="work-item-description-conflicts" - > + <gl-alert v-if="hasConflicts" :dismissible="false" variant="danger" class="gl-w-full"> <p> {{ s__( diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue index d95b434a829..c8ea2a12038 100644 --- a/app/assets/javascripts/work_items/components/work_item_detail.vue +++ b/app/assets/javascripts/work_items/components/work_item_detail.vue @@ -409,7 +409,7 @@ export default { </gl-skeleton-loader> </div> <template v-else> - <div class="gl-display-flex gl-align-items-center" data-testid="work-item-body"> + <div class="gl-display-flex gl-align-items-center"> <ul v-if="parentWorkItem" class="list-unstyled gl-display-flex gl-min-w-0 gl-mr-auto gl-mb-0 gl-z-index-0" diff --git a/app/assets/javascripts/work_items/components/work_item_milestone.vue b/app/assets/javascripts/work_items/components/work_item_milestone.vue index 867d25702d8..fe09105e173 100644 --- a/app/assets/javascripts/work_items/components/work_item_milestone.vue +++ b/app/assets/javascripts/work_items/components/work_item_milestone.vue @@ -225,7 +225,6 @@ export default { <gl-dropdown v-else id="milestone-value" - data-testid="work-item-milestone-dropdown" class="gl-pl-0 gl-max-w-full work-item-field-value" :toggle-class="dropdownClasses" :text="dropdownText" diff --git a/app/assets/javascripts/work_items/components/work_item_state_toggle_button.vue b/app/assets/javascripts/work_items/components/work_item_state_toggle_button.vue index 7edda2592de..6d7a93f64c4 100644 --- a/app/assets/javascripts/work_items/components/work_item_state_toggle_button.vue +++ b/app/assets/javascripts/work_items/components/work_item_state_toggle_button.vue @@ -104,10 +104,7 @@ export default { </script> <template> - <gl-button - :loading="updateInProgress" - data-testid="work-item-state-toggle" - @click="updateWorkItem" - >{{ toggleWorkItemStateText }}</gl-button - > + <gl-button :loading="updateInProgress" @click="updateWorkItem">{{ + toggleWorkItemStateText + }}</gl-button> </template> diff --git a/app/assets/javascripts/work_items/components/work_item_todos.vue b/app/assets/javascripts/work_items/components/work_item_todos.vue index e6d7f2067ba..d5633adec9a 100644 --- a/app/assets/javascripts/work_items/components/work_item_todos.vue +++ b/app/assets/javascripts/work_items/components/work_item_todos.vue @@ -175,17 +175,12 @@ export default { <template> <gl-button v-gl-tooltip.hover - data-testid="work-item-todos-action" :loading="isLoading" :title="buttonLabel" category="tertiary" :aria-label="buttonLabel" @click="onToggle" > - <gl-icon - data-testid="work-item-todos-icon" - :class="{ 'gl-fill-blue-500': pendingTodo }" - :name="buttonIcon" - /> + <gl-icon :class="{ 'gl-fill-blue-500': pendingTodo }" :name="buttonIcon" /> </gl-button> </template> diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js index 8de539f06f7..e4fa277485a 100644 --- a/app/assets/javascripts/work_items/constants.js +++ b/app/assets/javascripts/work_items/constants.js @@ -246,7 +246,6 @@ export const WORK_ITEM_ACTIVITY_SORT_OPTIONS = [ ]; export const TEST_ID_CONFIDENTIALITY_TOGGLE_ACTION = 'confidentiality-toggle-action'; -export const TEST_ID_NOTIFICATIONS_TOGGLE_ACTION = 'notifications-toggle-action'; export const TEST_ID_NOTIFICATIONS_TOGGLE_FORM = 'notifications-toggle-form'; export const TEST_ID_DELETE_ACTION = 'delete-action'; export const TEST_ID_PROMOTE_ACTION = 'promote-action'; diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md index 736f381e9d7..ba1a4ca05c4 100644 --- a/doc/administration/audit_events.md +++ b/doc/administration/audit_events.md @@ -6,171 +6,146 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Audit events **(PREMIUM ALL)** -Use audit events to track important events, including who performed the related action and when. -You can use audit events to track, for example: +A security audit is a in-depth analysis and review of your infrastructure, which is used to display +areas of concern and potentially hazardous practices. To assist with the audit process, GitLab provides +audit events which allow you to track a variety of different actions within GitLab. + +For example, you can use audit events to track: - Who changed the permission level of a particular user for a GitLab project, and when. - Who added a new user or removed a user, and when. -Audit events are similar to the [log system](logs/index.md). - -The GitLab API, database, and `audit_json.log` record many audit events. Some audit events are only available through -[streaming audit events](audit_event_streaming.md). +These events can be used to in an audit to assess risk, strengthen security measures, respond to incidents, and adhere to compliance. For a complete list the audit events GitLab provides, see [Audit event types](../administration/audit_event_streaming/audit_event_types.md). -You can also generate an [audit report](audit_reports.md) of audit events. +## Prerequisites -NOTE: -You can't configure a retention policy for audit events, but epic -[7917](https://gitlab.com/groups/gitlab-org/-/epics/7917) proposes to change this. +To view specific types of audit events, you need a minimum role. -## Time zones - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/242014) in GitLab 15.7, GitLab UI shows dates and times in the user's local time zone instead of UTC. +- To view the group audit events of all users in a group, you must have the [Owner role](../user/permissions.md#roles) for the group. +- To view the project audit events of all users in a project, you must have at least the [Maintainer role](../user/permissions.md#roles) for the project. +- To view the group and project audit events based on your own actions in a group or project, you must have at least the [Developer role](../user/permissions.md#roles) + for the group or project. -The time zone used for audit events depends on where you view them: +Users with the [Auditor access level](auditor_users.md) can see group and project events for all users. -- In GitLab UI, your local time zone (GitLab 15.7 and later) or UTC (GitLab 15.6 and earlier) is used. -- The [Audit Events API](../api/audit_events.md) returns dates and times in UTC by default, or the - [configured time zone](timezone.md) on a self-managed GitLab instance. -- In `audit_json.log`, UTC is used. -- In CSV exports, UTC is used. +## Viewing audit events -## View audit events +Audit events can be viewed at the group, project, instance, and sign-in level. Each level has different audit events which it logs. -Depending on the events you want to view, at a minimum you must have: - -- For group audit events of all users in the group, the Owner role for the group. -- For project audit events of all users in the project, the Maintainer role for the project. -- For group and project audit events based on your own actions, the Developer role for the group or project. -- [Auditor users](auditor_users.md) can see group and project events for all users. - -You can view audit events scoped to a group or project. +### Group audit events To view a group's audit events: -1. Go to the group. +1. On the left sidebar, select **Search or go to** and find your group. 1. On the left sidebar, select **Secure > Audit events**. +1. Filter the audit events by the member of the project (user) who performed the action and date range. -Group events do not include project audit events. Group events can also be accessed using the -[Group Audit Events API](../api/audit_events.md#group-audit-events). Group event queries are limited to a maximum of 30 -days. +Group audit events can also be accessed using the [Group Audit Events API](../api/audit_events.md#group-audit-events). Group audit event queries are limited to a maximum of 30 days. -To view a project's audit events: +### Project audit events -1. Go to the project. +1. On the left sidebar, select **Search or go to** and find your project. 1. On the left sidebar, select **Secure > Audit events**. +1. Filter the audit events by the member of the project (user) who performed the action and date range. -Project events can also be accessed using the [Project Audit Events API](../api/audit_events.md#project-audit-events). -Project event queries are limited to a maximum of 30 days. +Project audit events can also be accessed using the [Project Audit Events API](../api/audit_events.md#project-audit-events). Project audit event queries are limited to a maximum of 30 days. -## View instance audit events **(PREMIUM SELF)** +### Instance audit events **(PREMIUM SAAS)** You can view audit events from user actions across an entire GitLab instance. - To view instance audit events: 1. On the left sidebar, select **Search or go to**. 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Audit Events**. +1. Filter by the following: + - Member of the project (user) who performed the action + - Group + - Project + - Date Range + +### Sign-in audit events **(FREE ALL)** + +Successful sign-in events are the only audit events available at all tiers. To see successful sign-in events: + +1. On the left sidebar, select your avatar. +1. Select **Edit profile > Authentication log**. -### Export to CSV +After upgrading to a paid tier, you can also see successful sign-in events on audit event pages. + +## Exporting audit events > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/1449) in GitLab 13.4. > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/285441) in GitLab 13.7. > - Entity type `Gitlab::Audit::InstanceScope` for instance audit events [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/418185) in GitLab 16.2. -You can export the current view (including filters) of your instance audit events as a CSV file. To export the instance -audit events to CSV: +You can export the current view (including filters) of your instance audit events as a +CSV(comma-separated values) file. To export the instance audit events to CSV: 1. On the left sidebar, select **Search or go to**. 1. Select **Admin Area**. 1. On the left sidebar, select **Monitoring > Audit Events**. -1. Select the available search [filters](#filter-audit-events). +1. Select the available search filters. 1. Select **Export as CSV**. -The exported file: - -- Is sorted by `created_at` in ascending order. -- Is limited to a maximum of 100 000 events. The remaining records are truncated when this limit is reached. - -Data is encoded with: - -- Comma as the column delimiter. -- `"` to quote fields if necessary. -- New lines separate rows. +A download confirmation dialog then appears for you to download the CSV file. The exported CSV is limited +to a maximum of 100000 events. The remaining records are truncated when this limit is reached. -The first row contains the headers, which are listed in the following table along with a description of the values: +### Audit event CSV encoding -| Column | Description | -|:---------------------|:-------------------------------------------------------------------| -| **ID** | Audit event `id`. | -| **Author ID** | ID of the author. | -| **Author Name** | Full name of the author. | -| **Entity ID** | ID of the scope. | -| **Entity Type** | Type of the scope (`Project`, `Group`, `User`, or `Gitlab::Audit::InstanceScope`). | -| **Entity Path** | Path of the scope. | -| **Target ID** | ID of the target. | -| **Target Type** | Type of the target. | -| **Target Details** | Details of the target. | -| **Action** | Description of the action. | -| **IP Address** | IP address of the author who performed the action. | -| **Created At (UTC)** | Formatted as `YYYY-MM-DD HH:MM:SS`. | +The exported CSV file is encoded as follows: -## View sign-in events **(FREE ALL)** +- `,` is used as the column delimiter +- `"` is used to quote fields if necessary. +- `\n` is used to separate rows. -Successful sign-in events are the only audit events available at all tiers. To see successful sign-in events: +The first row contains the headers, which are listed in the following table along +with a description of the values: -1. On the left sidebar, select your avatar. -1. Select **Edit profile > Authentication log**. - -After upgrading to a paid tier, you can also see successful sign-in events on audit event pages. +| Column | Description | +| --------------------- | ---------------------------------------------------------------------------------- | +| **ID** | Audit event `id`. | +| **Author ID** | ID of the author. | +| **Author Name** | Full name of the author. | +| **Entity ID** | ID of the scope. | +| **Entity Type** | Type of the scope (`Project`, `Group`, `User`, or `Gitlab::Audit::InstanceScope`). | +| **Entity Path** | Path of the scope. | +| **Target ID** | ID of the target. | +| **Target Type** | Type of the target. | +| **Target Details** | Details of the target. | +| **Action** | Description of the action. | +| **IP Address** | IP address of the author who performed the action. | +| **Created At (UTC)** | Formatted as `YYYY-MM-DD HH:MM:SS`. | -## Filter audit events - -From audit events pages, different filters are available depending on the page you're on. - -| Audit event page | Available filter | -|:-----------------|:-----------------------------------------------------------------------------------------------------------------------| -| Project | User (member of the project) who performed the action. | -| Group | User (member of the group) who performed the action. | -| Instance | Group, project, or user. | -| All | Date range buttons and pickers (maximum range of 31 days). Default is from the first day of the month to today's date. | +All items are sorted by `created_at` in ascending order. ## User impersonation > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/536) in GitLab 13.0. > - Impersonation session events included in group audit events in GitLab 14.8. -When a user is [impersonated](../administration/admin_area.md#user-impersonation), their actions are logged as audit events -with additional details: +When a user is [impersonated](../administration/admin_area.md#user-impersonation), their actions are logged as audit events with the following additional details: -- Audit events include information about the impersonating administrator. These audit events are visible in audit event - pages depending on the audit event type (group, project, or user). -- Extra audit events are recorded for the start and end of the administrator's impersonation session. These audit events - are visible as: - - Instance audit events. - - Group audit events for all groups the user belongs to. For performance reasons, group audit events are limited to - the oldest 20 groups you belong to. +- Audit events include information about the impersonating administrator. +- Extra audit events are recorded for the start and end of the administrator's impersonation session. ![Audit event with impersonated user](img/impersonated_audit_events_v15_7.png) -## Available audit events +## Time zones -For a list of available audit events, see [Audit event types](../administration/audit_event_streaming/audit_event_types.md). +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/242014) in GitLab 15.7, GitLab UI shows dates and times in the user's local time zone instead of UTC. -## Unsupported events +The time zone used for audit events depends on where you view them: -Some events are not tracked in audit events. The following epics and issues propose support for more events: +- In GitLab UI, your local time zone (GitLab 15.7 and later) or UTC (GitLab 15.6 and earlier) is used. +- The [Audit Events API](../api/audit_events.md) returns dates and times in UTC by default, or the + [configured time zone](timezone.md) on a self-managed GitLab instance. +- In CSV exports, UTC is used. -- [Project settings and activity](https://gitlab.com/groups/gitlab-org/-/epics/474). -- [Group settings and activity](https://gitlab.com/groups/gitlab-org/-/epics/475). -- [Instance-level settings and activity](https://gitlab.com/groups/gitlab-org/-/epics/476). -- [Deployment Approval activity](https://gitlab.com/gitlab-org/gitlab/-/issues/354782). -- [Approval rules processing by a non GitLab user](https://gitlab.com/gitlab-org/gitlab/-/issues/407384). +## Contribute to audit events If you don't see the event you want in any of the epics, you can either: - Use the **Audit Event Proposal** issue template to - [create an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Audit%20Event%20Proposal) to - request it. + [create an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Audit%20Event%20Proposal) to request it. - [Add it yourself](../development/audit_event_guide/index.md). diff --git a/doc/development/export_csv.md b/doc/development/export_csv.md index 9b0205166bf..ce0a6e026ff 100644 --- a/doc/development/export_csv.md +++ b/doc/development/export_csv.md @@ -10,7 +10,7 @@ This document lists the different implementations of CSV export in GitLab codeba | Export type | How it works | Advantages | Disadvantages | Existing examples | |---|---|---|---|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Streaming | - Query and yield data in batches to a response stream.<br>- Download starts immediately. | - Report available immediately. | - No progress indicator.<br>- Requires a reliable connection. | [Export Audit Event Log](../administration/audit_events.md#export-to-csv) | +| Streaming | - Query and yield data in batches to a response stream.<br>- Download starts immediately. | - Report available immediately. | - No progress indicator.<br>- Requires a reliable connection. | [Export Audit Event Log](../administration/audit_events.md#exporting-audit-events) | | Downloading | - Query and write data in batches to a temporary file.<br>- Loads the file into memory.<br>- Sends the file to the client. | - Report available immediately. | - Large amount of data might cause request timeout.<br>- Memory intensive.<br>- Request expires when user navigates to a different page. | - [Export Chain of Custody Report](../user/compliance/compliance_center/index.md#chain-of-custody-report)<br>- [Export License Usage File](../subscriptions/self_managed/index.md#export-your-license-usage) | | As email attachment | - Asynchronously process the query with background job.<br>- Email uses the export as an attachment. | - Asynchronous processing. | - Requires users use a different app (email) to download the CSV.<br>- Email providers may limit attachment size. | - [Export issues](../user/project/issues/csv_export.md)<br>- [Export merge requests](../user/project/merge_requests/csv_export.md) | | As downloadable link in email (*) | - Asynchronously process the query with background job.<br>- Email uses an export link. | - Asynchronous processing.<br>- Bypasses email provider attachment size limit. | - Requires users use a different app (email).<br>- Requires additional storage and cleanup. | [Export User Permissions](https://gitlab.com/gitlab-org/gitlab/-/issues/1772) | diff --git a/doc/install/aws/manual_install_aws.md b/doc/install/aws/manual_install_aws.md index a952180674c..cd42e689c41 100644 --- a/doc/install/aws/manual_install_aws.md +++ b/doc/install/aws/manual_install_aws.md @@ -787,7 +787,7 @@ and primarily the restore prerequisites. Then, follow the steps under the ## Updating GitLab -GitLab releases a new version every month on the 22nd. Whenever a new version is +GitLab releases a new version every month on the [release date](https://about.gitlab.com/releases/). Whenever a new version is released, you can update your GitLab instance: 1. SSH into your instance diff --git a/doc/user/group/manage.md b/doc/user/group/manage.md index d67e52a6fc3..b2ca9c35d37 100644 --- a/doc/user/group/manage.md +++ b/doc/user/group/manage.md @@ -513,7 +513,7 @@ To disable third-party AI features for a group: 1. Select **Save changes**. When Code Suggestions are enabled and disabled, an -[audit event](../../administration/audit_events.md#view-audit-events) is created. +[audit event](../../administration/audit_events.md) is created. ## Group activity analytics **(PREMIUM ALL)** diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 8de70afd7fa..c98b7517327 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -41983,6 +41983,9 @@ msgstr "" msgid "ScanResultPolicy|Prevent branch protection modification" msgstr "" +msgid "ScanResultPolicy|Prevent pushing and force pushing" +msgstr "" + msgid "ScanResultPolicy|Protected branch settings" msgstr "" diff --git a/package.json b/package.json index df5c27b8e9d..80b869465e2 100644 --- a/package.json +++ b/package.json @@ -49,8 +49,8 @@ "@apollo/client": "^3.5.10", "@babel/core": "^7.18.5", "@babel/preset-env": "^7.18.2", - "@cubejs-client/core": "^0.34.2", - "@cubejs-client/vue": "^0.34.2", + "@cubejs-client/core": "^0.34.9", + "@cubejs-client/vue": "^0.34.9", "@floating-ui/dom": "^1.2.9", "@gitlab/application-sdk-browser": "^0.2.8", "@gitlab/at.js": "1.5.7", diff --git a/spec/features/projects/work_items/work_item_spec.rb b/spec/features/projects/work_items/work_item_spec.rb index 2419effab94..09a8636359d 100644 --- a/spec/features/projects/work_items/work_item_spec.rb +++ b/spec/features/projects/work_items/work_item_spec.rb @@ -19,9 +19,7 @@ RSpec.describe 'Work item', :js, feature_category: :team_planning do context 'for signed in user' do before do project.add_developer(user) - sign_in(user) - visit work_items_path end @@ -38,7 +36,7 @@ RSpec.describe 'Work item', :js, feature_category: :team_planning do end it 'actions dropdown is displayed' do - expect(page).to have_selector('[data-testid="work-item-actions-dropdown"]') + expect(page).to have_button _('More actions') end it 'reassigns to another user', @@ -75,9 +73,7 @@ RSpec.describe 'Work item', :js, feature_category: :team_planning do context 'for signed in owner' do before do project.add_owner(user) - sign_in(user) - visit work_items_path end @@ -87,9 +83,7 @@ RSpec.describe 'Work item', :js, feature_category: :team_planning do context 'for guest users' do before do project.add_guest(user) - sign_in(user) - visit work_items_path end @@ -114,14 +108,12 @@ RSpec.describe 'Work item', :js, feature_category: :team_planning do end it 'todos action is not displayed' do - expect(page).not_to have_selector('[data-testid="work-item-todos-action"]') + expect(page).not_to have_button s_('WorkItem|Add a to do') end it 'award button is disabled and add reaction is not displayed' do - within('[data-testid="work-item-award-list"]') do - expect(page).not_to have_selector('[data-testid="emoji-picker"]') - expect(page).to have_selector('[data-testid="award-button"].disabled') - end + expect(page).not_to have_button _('Add reaction') + expect(page).to have_selector('[data-testid="award-button"].disabled') end it 'assignees input field is disabled' do diff --git a/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js b/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js index 6a24987b737..596283a9590 100644 --- a/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js +++ b/spec/frontend/work_items/components/notes/work_item_note_actions_spec.js @@ -1,4 +1,4 @@ -import { GlDisclosureDropdown } from '@gitlab/ui'; +import { GlButton, GlDisclosureDropdown } from '@gitlab/ui'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; @@ -17,7 +17,7 @@ describe('Work Item Note Actions', () => { const showSpy = jest.fn(); const findReplyButton = () => wrapper.findComponent(ReplyButton); - const findEditButton = () => wrapper.findByTestId('edit-work-item-note'); + const findEditButton = () => wrapper.findComponent(GlButton); const findEmojiButton = () => wrapper.findByTestId('note-emoji-button'); const findDropdown = () => wrapper.findComponent(GlDisclosureDropdown); const findDeleteNoteButton = () => wrapper.findByTestId('delete-note-action'); diff --git a/spec/frontend/work_items/components/work_item_actions_spec.js b/spec/frontend/work_items/components/work_item_actions_spec.js index 15c33bf5b1e..b41014a236b 100644 --- a/spec/frontend/work_items/components/work_item_actions_spec.js +++ b/spec/frontend/work_items/components/work_item_actions_spec.js @@ -12,7 +12,6 @@ import toast from '~/vue_shared/plugins/global_toast'; import WorkItemActions from '~/work_items/components/work_item_actions.vue'; import { TEST_ID_CONFIDENTIALITY_TOGGLE_ACTION, - TEST_ID_NOTIFICATIONS_TOGGLE_ACTION, TEST_ID_NOTIFICATIONS_TOGGLE_FORM, TEST_ID_DELETE_ACTION, TEST_ID_PROMOTE_ACTION, @@ -44,8 +43,6 @@ describe('WorkItemActions component', () => { const findModal = () => wrapper.findComponent(GlModal); const findConfidentialityToggleButton = () => wrapper.findByTestId(TEST_ID_CONFIDENTIALITY_TOGGLE_ACTION); - const findNotificationsToggleButton = () => - wrapper.findByTestId(TEST_ID_NOTIFICATIONS_TOGGLE_ACTION); const findDeleteButton = () => wrapper.findByTestId(TEST_ID_DELETE_ACTION); const findPromoteButton = () => wrapper.findByTestId(TEST_ID_PROMOTE_ACTION); const findCopyReferenceButton = () => wrapper.findByTestId(TEST_ID_COPY_REFERENCE_ACTION); @@ -248,7 +245,7 @@ describe('WorkItemActions component', () => { }); it('renders toggle button', () => { - expect(findNotificationsToggleButton().exists()).toBe(true); + expect(findNotificationsToggle().exists()).toBe(true); }); it.each` diff --git a/spec/support/shared_examples/features/content_editor_shared_examples.rb b/spec/support/shared_examples/features/content_editor_shared_examples.rb index edb8e6bb2ff..5271b5bd45c 100644 --- a/spec/support/shared_examples/features/content_editor_shared_examples.rb +++ b/spec/support/shared_examples/features/content_editor_shared_examples.rb @@ -560,6 +560,7 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { it 'adds the correct prefix for /assign' do type_in_content_editor '/assign' + expect(find(suggestions_dropdown)).to have_text('/assign') send_keys [:arrow_down, :enter] expect(page).to have_text('/assign @') @@ -568,6 +569,7 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { it 'adds the correct prefix for /label' do type_in_content_editor '/label' + expect(find(suggestions_dropdown)).to have_text('/label') send_keys [:arrow_down, :enter] expect(page).to have_text('/label ~') @@ -576,6 +578,7 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { it 'adds the correct prefix for /milestone' do type_in_content_editor '/milestone' + expect(find(suggestions_dropdown)).to have_text('/milestone') send_keys [:arrow_down, :enter] expect(page).to have_text('/milestone %') @@ -597,6 +600,39 @@ RSpec.shared_examples 'edits content using the content editor' do |params = { expect(page).to have_text('@abc123') end + it 'allows dismissing the suggestion popup and typing more text' do + type_in_content_editor '@ab' + + expect(find(suggestions_dropdown)).to have_text('abc123') + + send_keys :escape + + expect(page).not_to have_css(suggestions_dropdown) + + type_in_content_editor :enter + type_in_content_editor 'foobar' + + # ensure that the texts are in separate paragraphs + expect(page).to have_selector('p', text: '@ab') + expect(page).to have_selector('p', text: 'foobar') + expect(page).not_to have_selector('p', text: '@abfoobar') + end + + it 'allows typing more text after the popup has disappeared because no suggestions match' do + type_in_content_editor '@ab' + + expect(find(suggestions_dropdown)).to have_text('abc123') + + type_in_content_editor 'foo' + type_in_content_editor :enter + type_in_content_editor 'bar' + + # ensure that the texts are in separate paragraphs + expect(page).to have_selector('p', text: '@abfoo') + expect(page).to have_selector('p', text: 'bar') + expect(page).not_to have_selector('p', text: '@abfoobar') + end + context 'when `disable_all_mention` is enabled' do before do stub_feature_flags(disable_all_mention: true) diff --git a/spec/support/shared_examples/features/work_items_shared_examples.rb b/spec/support/shared_examples/features/work_items_shared_examples.rb index 69d6521e5a0..8c577749107 100644 --- a/spec/support/shared_examples/features/work_items_shared_examples.rb +++ b/spec/support/shared_examples/features/work_items_shared_examples.rb @@ -8,7 +8,6 @@ RSpec.shared_examples 'work items title' do find(title_selector).set("Work item title") find(title_selector).native.send_keys(:return) - wait_for_requests expect(work_item.reload.title).to eq 'Work item title' @@ -16,54 +15,37 @@ RSpec.shared_examples 'work items title' do end RSpec.shared_examples 'work items toggle status button' do - let(:state_button) { '[data-testid="work-item-state-toggle"]' } - it 'successfully shows and changes the status of the work item' do - expect(find(state_button, match: :first)).to have_content 'Close' + click_button 'Close', match: :first - find(state_button, match: :first).click - - wait_for_requests - - expect(find(state_button, match: :first)).to have_content 'Reopen' + expect(page).to have_button 'Reopen' expect(work_item.reload.state).to eq('closed') end end RSpec.shared_examples 'work items comments' do |type| - let(:form_selector) { '[data-testid="work-item-add-comment"]' } - let(:edit_button) { '[data-testid="edit-work-item-note"]' } - let(:textarea_selector) { '[data-testid="work-item-add-comment"] #work-item-add-or-edit-comment' } let(:is_mac) { page.evaluate_script('navigator.platform').include?('Mac') } let(:modifier_key) { is_mac ? :command : :control } - let(:comment) { 'Test comment' } def set_comment - find(form_selector).fill_in(with: comment) + fill_in _('Add a reply'), with: 'Test comment' end it 'successfully creates and shows comments' do set_comment - click_button "Comment" - wait_for_requests - page.within(".main-notes-list") do - expect(page).to have_content comment + expect(page).to have_text 'Test comment' end end it 'successfully updates existing comments' do set_comment click_button "Comment" - wait_for_all_requests - - find(edit_button).click + click_button _('Edit comment') send_keys(" updated") - click_button "Save comment" - - wait_for_all_requests + click_button _('Save comment') page.within(".main-notes-list") do expect(page).to have_content "Test comment updated" @@ -79,39 +61,31 @@ RSpec.shared_examples 'work items comments' do |type| it 'shows work item note actions' do set_comment - send_keys([modifier_key, :enter]) - wait_for_requests page.within(".main-notes-list") do - expect(page).to have_content comment + expect(page).to have_text 'Test comment' end page.within('.timeline-entry.note.note-wrapper.note-comment:last-child') do - expect(page).to have_selector('[data-testid="work-item-note-actions"]') - - find('[data-testid="work-item-note-actions"]').click + click_button _('More actions') - expect(page).to have_selector('[data-testid="copy-link-action"]') - expect(page).to have_selector('[data-testid="assign-note-action"]') - expect(page).to have_selector('[data-testid="delete-note-action"]') - expect(page).to have_selector('[data-testid="edit-work-item-note"]') + expect(page).to have_button _('Copy link') + expect(page).to have_button _('Assign to commenting user') + expect(page).to have_button _('Delete comment') + expect(page).to have_button _('Edit comment') end end end it 'successfully posts comments using shortcut and checks if textarea is blank when reinitiated' do set_comment - send_keys([modifier_key, :enter]) - wait_for_requests - page.within(".main-notes-list") do - expect(page).to have_content comment + expect(page).to have_content 'Test comment' end - - expect(find(textarea_selector)).to have_content "" + expect(page).to have_field _('Add a reply'), with: '' end context 'when using quick actions' do @@ -158,9 +132,7 @@ RSpec.shared_examples 'work items comments' do |type| end def click_reply_and_enter_slash - find(form_selector).fill_in(with: "/") - - wait_for_all_requests + fill_in _('Add a reply'), with: '/' end end end @@ -171,7 +143,6 @@ RSpec.shared_examples 'work items assignees' do # The button is only when the mouse is over the input find('[data-testid="work-item-assignees-input"]').fill_in(with: user.username) wait_for_requests - # submit and simulate blur to save send_keys(:enter) find("body").click @@ -182,21 +153,19 @@ RSpec.shared_examples 'work items assignees' do it 'successfully assigns the current user by clicking `Assign myself` button' do find('[data-testid="work-item-assignees-input"]').hover - find('[data-testid="assign-self"]').click - wait_for_requests + click_button _('Assign yourself') expect(work_item.reload.assignees).to include(user) end it 'successfully removes all users on clear all button click' do find('[data-testid="work-item-assignees-input"]').hover - find('[data-testid="assign-self"]').click - wait_for_requests + click_button _('Assign yourself') expect(work_item.reload.assignees).to include(user) find('[data-testid="work-item-assignees-input"]').click - find('[data-testid="clear-all-button"]').click + click_button 'Clear all' find("body").click wait_for_requests @@ -205,13 +174,12 @@ RSpec.shared_examples 'work items assignees' do it 'successfully removes user on clicking badge cross button' do find('[data-testid="work-item-assignees-input"]').hover - find('[data-testid="assign-self"]').click - wait_for_requests + click_button _('Assign yourself') expect(work_item.reload.assignees).to include(user) within('[data-testid="work-item-assignees-input"]') do - find('[data-testid="close-icon"]').click + click_button 'Close' end find("body").click wait_for_requests @@ -228,11 +196,9 @@ RSpec.shared_examples 'work items assignees' do end find('[data-testid="work-item-assignees-input"]').hover - find('[data-testid="assign-self"]').click - wait_for_requests + click_button _('Assign yourself') expect(work_item.reload.assignees).to include(user) - using_session :other_session do expect(work_item.reload.assignees).to include(user) end @@ -246,7 +212,6 @@ RSpec.shared_examples 'work items labels' do it 'successfully assigns a label' do find(labels_input_selector).fill_in(with: label.title) wait_for_requests - # submit and simulate blur to save send_keys(:enter) find(label_title_selector).click @@ -276,7 +241,6 @@ RSpec.shared_examples 'work items labels' do it 'removes all labels on clear all button click' do find(labels_input_selector).fill_in(with: label.title) wait_for_requests - send_keys(:enter) find(label_title_selector).click wait_for_requests @@ -285,9 +249,8 @@ RSpec.shared_examples 'work items labels' do within(labels_input_selector) do find('input').click - find('[data-testid="clear-all-button"]').click + click_button 'Clear all' end - find(label_title_selector).click wait_for_requests @@ -297,7 +260,6 @@ RSpec.shared_examples 'work items labels' do it 'removes label on clicking badge cross button' do find(labels_input_selector).fill_in(with: label.title) wait_for_requests - send_keys(:enter) find(label_title_selector).click wait_for_requests @@ -305,9 +267,8 @@ RSpec.shared_examples 'work items labels' do expect(page).to have_text(label.title) within(labels_input_selector) do - find('[data-testid="close-icon"]').click + click_button 'Remove label' end - find(label_title_selector).click wait_for_requests @@ -324,7 +285,6 @@ RSpec.shared_examples 'work items labels' do find(labels_input_selector).fill_in(with: label.title) wait_for_requests - send_keys(:enter) find(label_title_selector).click wait_for_requests @@ -341,10 +301,7 @@ end RSpec.shared_examples 'work items description' do it 'shows GFM autocomplete', :aggregate_failures do click_button "Edit description" - - find('[aria-label="Description"]').send_keys("@#{user.username}") - - wait_for_requests + fill_in _('Description'), with: "@#{user.username}" page.within('.atwho-container') do expect(page).to have_text(user.name) @@ -353,10 +310,7 @@ RSpec.shared_examples 'work items description' do it 'autocompletes available quick actions', :aggregate_failures do click_button "Edit description" - - find('[aria-label="Description"]').send_keys("/") - - wait_for_requests + fill_in _('Description'), with: '/' page.within('#at-view-commands') do expect(page).to have_text("title") @@ -378,8 +332,6 @@ RSpec.shared_examples 'work items description' do it 'shows conflict message when description changes', :aggregate_failures do click_button "Edit description" - wait_for_requests - ::WorkItems::UpdateService.new( container: work_item.project, current_user: other_user, @@ -388,11 +340,11 @@ RSpec.shared_examples 'work items description' do wait_for_requests - find('[aria-label="Description"]').send_keys("oh yeah!") + fill_in _('Description'), with: 'oh yeah!' - expect(page.find('[data-testid="work-item-description-conflicts"]')).to have_text(expected_warning) + expect(page).to have_text(expected_warning) - click_button "Save and overwrite" + click_button s_('WorkItem|Save and overwrite') expect(page.find('[data-testid="work-item-description"]')).to have_text("oh yeah!") end @@ -410,32 +362,23 @@ RSpec.shared_examples 'work items invite members' do click_button('Invite members') page.within invite_modal_selector do - expect(page).to have_content("You're inviting members to the #{work_item.project.name} project") + expect(page).to have_text("You're inviting members to the #{work_item.project.name} project") end end end RSpec.shared_examples 'work items milestone' do - def set_milestone(milestone_dropdown, milestone_text) - milestone_dropdown.click - - find('[data-testid="work-item-milestone-dropdown"] .gl-form-input', visible: true).send_keys "\"#{milestone_text}\"" - wait_for_requests - - click_button(milestone_text) - wait_for_requests - end - - let(:milestone_dropdown_selector) { '[data-testid="work-item-milestone-dropdown"]' } - it 'searches and sets or removes milestone for the work item' do - set_milestone(find(milestone_dropdown_selector), milestone.title) + click_button s_('WorkItem|Add to milestone') + send_keys "\"#{milestone.title}\"" + click_button milestone.title - expect(page.find(milestone_dropdown_selector)).to have_text(milestone.title) + expect(page).to have_button(milestone.title) - set_milestone(find(milestone_dropdown_selector), 'No milestone') + click_button milestone.title + click_button s_('WorkItem|No milestone') - expect(page.find(milestone_dropdown_selector)).to have_text('Add to milestone') + expect(page).to have_button(s_('WorkItem|Add to milestone')) end end @@ -443,56 +386,35 @@ RSpec.shared_examples 'work items comment actions for guest users' do context 'for guest user' do it 'hides other actions other than copy link' do page.within(".main-notes-list") do - expect(page).to have_selector('[data-testid="work-item-note-actions"]') + click_button _('More actions'), match: :first - find('[data-testid="work-item-note-actions"]', match: :first).click - expect(page).to have_selector('[data-testid="copy-link-action"]') - expect(page).not_to have_selector('[data-testid="assign-note-action"]') + expect(page).to have_button _('Copy link') + expect(page).not_to have_button _('Assign to commenting user') end end end end RSpec.shared_examples 'work items notifications' do - let(:actions_dropdown_selector) { '[data-testid="work-item-actions-dropdown"]' } - let(:notifications_toggle_selector) { '[data-testid="notifications-toggle-action"] button[role="switch"]' } - it 'displays toast when notification is toggled' do - find(actions_dropdown_selector).click + click_button _('More actions'), match: :first - page.within('[data-testid="notifications-toggle-form"]') do - expect(page).not_to have_css(".is-checked") + expect(page).not_to have_button(class: 'gl-toggle is-checked') - find(notifications_toggle_selector).click - wait_for_requests - - expect(page).to have_css(".is-checked") - end + click_button(class: 'gl-toggle') - page.within('.gl-toast') do - expect(find('.toast-body')).to have_content(_('Notifications turned on.')) - end + expect(page).to have_button(class: 'gl-toggle is-checked') + expect(page).to have_css('.gl-toast', text: _('Notifications turned on.')) end end RSpec.shared_examples 'work items todos' do - let(:todos_action_selector) { '[data-testid="work-item-todos-action"]' } - let(:todos_icon_selector) { '[data-testid="work-item-todos-icon"]' } - let(:header_section_selector) { '[data-testid="work-item-body"]' } - - def toggle_todo_action - find(todos_action_selector).click - wait_for_requests - end - it 'adds item to the list' do - page.within(header_section_selector) do - expect(find(todos_action_selector)['aria-label']).to eq('Add a to do') + expect(page).to have_button s_('WorkItem|Add a to do') - toggle_todo_action + click_button s_('WorkItem|Add a to do') - expect(find(todos_action_selector)['aria-label']).to eq('Mark as done') - end + expect(page).to have_button s_('WorkItem|Mark as done') page.within ".header-content span[aria-label='#{_('Todos count')}']" do expect(page).to have_content '1' @@ -500,12 +422,10 @@ RSpec.shared_examples 'work items todos' do end it 'marks a todo as done' do - page.within(header_section_selector) do - toggle_todo_action - toggle_todo_action - end + click_button s_('WorkItem|Add a to do') + click_button s_('WorkItem|Mark as done') - expect(find(todos_action_selector)['aria-label']).to eq('Add a to do') + expect(page).to have_button s_('WorkItem|Add a to do') expect(page).to have_selector(".header-content span[aria-label='#{_('Todos count')}']", visible: :hidden) end end @@ -514,7 +434,6 @@ RSpec.shared_examples 'work items award emoji' do let(:award_section_selector) { '.awards' } let(:award_button_selector) { '[data-testid="award-button"]' } let(:selected_award_button_selector) { '[data-testid="award-button"].selected' } - let(:emoji_picker_button_selector) { '[data-testid="emoji-picker"]' } let(:grinning_emoji_selector) { 'gl-emoji[data-name="grinning"]' } let(:tooltip_selector) { '.gl-tooltip' } @@ -560,7 +479,7 @@ RSpec.shared_examples 'work items award emoji' do it 'add custom award to the work item for current user' do within(award_section_selector) do - find(emoji_picker_button_selector).click + click_button _('Add reaction') find(grinning_emoji_selector).click expect(page).to have_selector(grinning_emoji_selector) diff --git a/yarn.lock b/yarn.lock index a5067af2d15..ccdf9749b90 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1025,10 +1025,10 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-3.0.0.tgz#798622546b63847e82389e473fd67f2707d82247" integrity sha512-hBI9tfBtuPIi885ZsZ32IMEU/5nlZH/KOVYJCOh7gyMxaVLGmLedYqFN6Ui1LXkI8JlC8IsuC0rF0btcRZKd5g== -"@cubejs-client/core@^0.34.2": - version "0.34.2" - resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.34.2.tgz#a063a605a8c824bc465c786c7ef8d54d916aed1c" - integrity sha512-KnVw2w2TfOcnUJ6a79M+z9k83h7Bp+2NgX5ADwuIiJLU13HmT5p/BJGGo7A5BLOrRs25+e0SdJsGYmT/R0ViyA== +"@cubejs-client/core@^0.34.9": + version "0.34.9" + resolved "https://registry.yarnpkg.com/@cubejs-client/core/-/core-0.34.9.tgz#a402450b08e52ef7b87d44a6044910d94218783b" + integrity sha512-F1+VHnhZt3t+709PoFzaNdqKiQ1QaLAiDcU/S5/yZlohU4pYOL4I57nA/AaFqg9XTJd2/cUPCkvrxBtft3xoJA== dependencies: "@babel/runtime" "^7.1.2" core-js "^3.6.5" @@ -1038,12 +1038,12 @@ url-search-params-polyfill "^7.0.0" uuid "^8.3.2" -"@cubejs-client/vue@^0.34.2": - version "0.34.2" - resolved "https://registry.yarnpkg.com/@cubejs-client/vue/-/vue-0.34.2.tgz#bdc44763b9dbb828a2b22c9b2e84b28e35046275" - integrity sha512-9hOO8V9m1HxJqWomsJEg+O0GdNXmfmOXsSZPuUeFdPsR0mW6i3mOa3Blbo0HpmMdy5ui3Sc449gZC0+/dXKRXw== +"@cubejs-client/vue@^0.34.9": + version "0.34.9" + resolved "https://registry.yarnpkg.com/@cubejs-client/vue/-/vue-0.34.9.tgz#2a39db0099829304f9f42e6a2a19bc9be597cb8e" + integrity sha512-nbhaXvXdN9+NpFYdDsH+QVfDvD+sduRixoKRVbh3ImkIeMRcRAyv404+W62rQy3qhzINDivTnKNRtch1bS+xLA== dependencies: - "@cubejs-client/core" "^0.34.2" + "@cubejs-client/core" "^0.34.9" core-js "^3.6.5" ramda "^0.27.2" |