Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e67a224437
commit
65edff9059
|
|
@ -89,6 +89,7 @@ export default {
|
||||||
v-gl-tooltip.hover
|
v-gl-tooltip.hover
|
||||||
category="secondary"
|
category="secondary"
|
||||||
data-testid="subscribe-button"
|
data-testid="subscribe-button"
|
||||||
|
:data-subscribed="subscribedToNotifications ? 'true' : 'false'"
|
||||||
:title="notificationTooltip"
|
:title="notificationTooltip"
|
||||||
class="btn-icon"
|
class="btn-icon"
|
||||||
@click="toggleNotifications(!subscribedToNotifications)"
|
@click="toggleNotifications(!subscribedToNotifications)"
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import {
|
||||||
BASE_ALLOWED_CREATE_TYPES,
|
BASE_ALLOWED_CREATE_TYPES,
|
||||||
WORK_ITEM_TYPE_NAME_ISSUE,
|
WORK_ITEM_TYPE_NAME_ISSUE,
|
||||||
WORK_ITEM_TYPE_NAME_INCIDENT,
|
WORK_ITEM_TYPE_NAME_INCIDENT,
|
||||||
|
WORK_ITEM_TYPE_NAME_TASK,
|
||||||
} from '../constants';
|
} from '../constants';
|
||||||
import workItemRelatedItemQuery from '../graphql/work_item_related_item.query.graphql';
|
import workItemRelatedItemQuery from '../graphql/work_item_related_item.query.graphql';
|
||||||
import { convertTypeEnumToName } from '../utils';
|
import { convertTypeEnumToName } from '../utils';
|
||||||
|
|
@ -69,14 +70,17 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
isIssue() {
|
|
||||||
return this.workItemType === WORK_ITEM_TYPE_NAME_ISSUE;
|
|
||||||
},
|
|
||||||
isIncident() {
|
isIncident() {
|
||||||
return this.workItemType === WORK_ITEM_TYPE_NAME_INCIDENT;
|
return this.workItemType === WORK_ITEM_TYPE_NAME_INCIDENT;
|
||||||
},
|
},
|
||||||
allowedWorkItemTypes() {
|
allowedWorkItemTypes() {
|
||||||
if (this.isIssue || this.isIncident) {
|
if (
|
||||||
|
[
|
||||||
|
WORK_ITEM_TYPE_NAME_ISSUE,
|
||||||
|
WORK_ITEM_TYPE_NAME_INCIDENT,
|
||||||
|
WORK_ITEM_TYPE_NAME_TASK,
|
||||||
|
].includes(this.workItemType)
|
||||||
|
) {
|
||||||
return BASE_ALLOWED_CREATE_TYPES;
|
return BASE_ALLOWED_CREATE_TYPES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -150,7 +154,7 @@ export default {
|
||||||
:is-group="isGroup"
|
:is-group="isGroup"
|
||||||
:related-item="relatedItem"
|
:related-item="relatedItem"
|
||||||
:should-discard-draft="shouldDiscardDraft"
|
:should-discard-draft="shouldDiscardDraft"
|
||||||
:always-show-work-item-type-select="isIncident || isIssue"
|
:always-show-work-item-type-select="!isGroup"
|
||||||
:allowed-work-item-types="allowedWorkItemTypes"
|
:allowed-work-item-types="allowedWorkItemTypes"
|
||||||
@updateType="updateWorkItemType($event)"
|
@updateType="updateWorkItemType($event)"
|
||||||
@confirmCancel="handleConfirmCancellation"
|
@confirmCancel="handleConfirmCancellation"
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ class Groups::BoardsController < Groups::ApplicationController
|
||||||
push_frontend_feature_flag(:board_multi_select, group)
|
push_frontend_feature_flag(:board_multi_select, group)
|
||||||
push_frontend_feature_flag(:issues_list_drawer, group)
|
push_frontend_feature_flag(:issues_list_drawer, group)
|
||||||
push_force_frontend_feature_flag(:work_items_beta, !!group&.work_items_beta_feature_flag_enabled?)
|
push_force_frontend_feature_flag(:work_items_beta, !!group&.work_items_beta_feature_flag_enabled?)
|
||||||
|
push_frontend_feature_flag(:notifications_todos_buttons)
|
||||||
|
push_force_frontend_feature_flag(:glql_integration, !!group&.glql_integration_feature_flag_enabled?)
|
||||||
|
push_force_frontend_feature_flag(:continue_indented_text, !!group&.continue_indented_text_feature_flag_enabled?)
|
||||||
|
push_frontend_feature_flag(:work_item_status_feature_flag, group&.root_ancestor)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature_category :team_planning
|
feature_category :team_planning
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,10 @@ class Projects::BoardsController < Projects::ApplicationController
|
||||||
push_frontend_feature_flag(:board_multi_select, project)
|
push_frontend_feature_flag(:board_multi_select, project)
|
||||||
push_frontend_feature_flag(:issues_list_drawer, project)
|
push_frontend_feature_flag(:issues_list_drawer, project)
|
||||||
push_force_frontend_feature_flag(:work_items_beta, !!project&.work_items_beta_feature_flag_enabled?)
|
push_force_frontend_feature_flag(:work_items_beta, !!project&.work_items_beta_feature_flag_enabled?)
|
||||||
|
push_frontend_feature_flag(:notifications_todos_buttons)
|
||||||
|
push_force_frontend_feature_flag(:glql_integration, !!project&.glql_integration_feature_flag_enabled?)
|
||||||
|
push_force_frontend_feature_flag(:continue_indented_text, !!project&.continue_indented_text_feature_flag_enabled?)
|
||||||
|
push_frontend_feature_flag(:work_item_status_feature_flag, project&.root_ancestor)
|
||||||
end
|
end
|
||||||
|
|
||||||
feature_category :team_planning
|
feature_category :team_planning
|
||||||
|
|
|
||||||
|
|
@ -74,18 +74,32 @@ validates :new_setting,
|
||||||
## Migrate a database column to a JSONB column
|
## Migrate a database column to a JSONB column
|
||||||
|
|
||||||
To migrate a column to JSONB, add the new setting under the JSONB accessor.
|
To migrate a column to JSONB, add the new setting under the JSONB accessor.
|
||||||
Follow the [process to add a new application setting](#add-a-new-application-setting).
|
|
||||||
|
|
||||||
You can use the same name as the existing column to maintain consistency. During the
|
### Adding the JSONB setting
|
||||||
transition period, Rails writes the same information to both the existing database
|
|
||||||
|
- Follow the [process to add a new application setting](#add-a-new-application-setting).
|
||||||
|
- Use the same name as the existing column to maintain consistency.
|
||||||
|
- During transition, Rails writes the same information to both the existing database
|
||||||
column and the field under the new JSONB column. This ensures data consistency and
|
column and the field under the new JSONB column. This ensures data consistency and
|
||||||
prevents downtime.
|
prevents downtime.
|
||||||
|
|
||||||
You must follow the [process for dropping columns](database/avoiding_downtime_in_migrations.md#dropping-columns) to remove the original column.
|
### Required cleanup steps
|
||||||
This a required multi-milestone process that involves:
|
|
||||||
|
You must follow the [process for dropping columns](database/avoiding_downtime_in_migrations.md#dropping-columns)
|
||||||
|
to remove the original column. This a required multi-milestone process that involves:
|
||||||
|
|
||||||
1. Ignoring the column.
|
1. Ignoring the column.
|
||||||
1. Dropping the column.
|
1. Dropping the column.
|
||||||
1. Removing the ignore rule.
|
1. Removing the ignore rule.
|
||||||
|
|
||||||
|
{{< alert type="warning" >}}
|
||||||
|
|
||||||
Dropping the original column before ignoring it in the model can cause problems with zero-downtime migrations.
|
Dropping the original column before ignoring it in the model can cause problems with zero-downtime migrations.
|
||||||
|
|
||||||
|
{{< /alert >}}
|
||||||
|
|
||||||
|
### Default values
|
||||||
|
|
||||||
|
When migrating settings to JSONB columns with `jsonb_accessor` defaults,
|
||||||
|
remove them from `ApplicationSettingImplementation.defaults` because
|
||||||
|
JSONB accessors take precedence over the `defaults` method.
|
||||||
|
|
|
||||||
|
|
@ -259,7 +259,6 @@ to the table's database dictionary file. This can be used for:
|
||||||
|
|
||||||
- JiHu specific tables, since they do not have any data on the .com database. [!145905](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/145905)
|
- JiHu specific tables, since they do not have any data on the .com database. [!145905](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/145905)
|
||||||
- tables that are marked to be dropped soon, like `operations_feature_flag_scopes`. [!147541](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147541)
|
- tables that are marked to be dropped soon, like `operations_feature_flag_scopes`. [!147541](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147541)
|
||||||
- tables that mandatorily need to be present per cell to support a cell's operations, have unique data per cell, but cannot have a sharding key defined. For example, `zoekt_nodes`.
|
|
||||||
|
|
||||||
When tables are exempted from sharding key requirements, they also do not show up in our
|
When tables are exempted from sharding key requirements, they also do not show up in our
|
||||||
[progress dashboard](https://cells-progress-tracker-gitlab-org-tenant-scale-g-f4ad96bf01d25f.gitlab.io/sharding_keys).
|
[progress dashboard](https://cells-progress-tracker-gitlab-org-tenant-scale-g-f4ad96bf01d25f.gitlab.io/sharding_keys).
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,10 @@ The `GITLAB_TOKEN` for the [@gl-service-dev-secure-analyzers-automation](https:/
|
||||||
|
|
||||||
The `ci-templates` project requires the `GITLAB_TOKEN` to allow certain scripts to execute API calls. This step can be removed after [allow JOB-TOKEN access to CI/lint endpoint](https://gitlab.com/gitlab-org/gitlab/-/issues/438781) has been completed.
|
The `ci-templates` project requires the `GITLAB_TOKEN` to allow certain scripts to execute API calls. This step can be removed after [allow JOB-TOKEN access to CI/lint endpoint](https://gitlab.com/gitlab-org/gitlab/-/issues/438781) has been completed.
|
||||||
|
|
||||||
|
1. `GITLAB_TOKEN` CI/CD variable for the [`gitlab-org/secure/tools/security-triage-automation`](https://gitlab.com/gitlab-org/secure/tools/security-triage-automation) project.
|
||||||
|
|
||||||
|
This must be explicitly configured because the `security-triage-automation` project is not nested under the `gitlab-org/security-products/analyzers` namespace, and therefore _does not inherit_ the `GITLAB_TOKEN` value.
|
||||||
|
|
||||||
1. `SEC_REGISTRY_PASSWORD` CI/CD variable for [`gitlab-advanced-sast`](https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-advanced-sast/-/settings/ci_cd#js-cicd-variables-settings).
|
1. `SEC_REGISTRY_PASSWORD` CI/CD variable for [`gitlab-advanced-sast`](https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-advanced-sast/-/settings/ci_cd#js-cicd-variables-settings).
|
||||||
|
|
||||||
This allows our [tagging script](https://gitlab.com/gitlab-org/security-products/ci-templates/blob/cfe285a/scripts/tag_image.sh) to pull from the private container registry in the development project `registry.gitlab.com/gitlab-org/security-products/analyzers/<analyzer-name>/tmp`, and push to the publicly accessible container registry `registry.gitlab.com/security-products/<analyzer-name>`.
|
This allows our [tagging script](https://gitlab.com/gitlab-org/security-products/ci-templates/blob/cfe285a/scripts/tag_image.sh) to pull from the private container registry in the development project `registry.gitlab.com/gitlab-org/security-products/analyzers/<analyzer-name>/tmp`, and push to the publicly accessible container registry `registry.gitlab.com/security-products/<analyzer-name>`.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ RSpec.describe 'Project issue boards sidebar', :js, feature_category: :portfolio
|
||||||
context 'when issues drawer is disabled' do
|
context 'when issues drawer is disabled' do
|
||||||
before do
|
before do
|
||||||
stub_feature_flags(issues_list_drawer: false)
|
stub_feature_flags(issues_list_drawer: false)
|
||||||
|
stub_feature_flags(notifications_todos_buttons: false)
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
|
|
||||||
visit project_board_path(project, board)
|
visit project_board_path(project, board)
|
||||||
|
|
|
||||||
|
|
@ -131,6 +131,18 @@ describe('WorkItemActions component', () => {
|
||||||
expect(findNotificationsButton().findComponent(GlIcon).props('name')).toBe(icon);
|
expect(findNotificationsButton().findComponent(GlIcon).props('name')).toBe(icon);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
scenario | subscribedToNotifications | dataSubscribed
|
||||||
|
${'notifications are off'} | ${false} | ${'false'}
|
||||||
|
${'notifications are on'} | ${true} | ${'true'}
|
||||||
|
`(
|
||||||
|
'has the correct data-subscribed attribute when $scenario',
|
||||||
|
({ subscribedToNotifications, dataSubscribed }) => {
|
||||||
|
createComponent({ subscribedToNotifications });
|
||||||
|
expect(findNotificationsButton().attributes('data-subscribed')).toBe(dataSubscribed);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
it('emits error when the update notification mutation fails', async () => {
|
it('emits error when the update notification mutation fails', async () => {
|
||||||
createComponent({
|
createComponent({
|
||||||
notificationsMutationHandler: toggleNotificationsFailureHandler,
|
notificationsMutationHandler: toggleNotificationsFailureHandler,
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,16 @@ describe('Create work item page component', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('passes alwaysShowWorkItemTypeSelect prop as `true` to the CreateWorkItem component when isGroup is false', () => {
|
||||||
|
const pushMock = jest.fn();
|
||||||
|
createComponent({ push: pushMock }, false);
|
||||||
|
|
||||||
|
expect(findCreateWorkItem().props()).toMatchObject({
|
||||||
|
alwaysShowWorkItemTypeSelect: true,
|
||||||
|
allowedWorkItemTypes: ['Incident', 'Issue', 'Task'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('visits work item detail page after create if router is not present', () => {
|
it('visits work item detail page after create if router is not present', () => {
|
||||||
createComponent();
|
createComponent();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ module InvokeRopSteps
|
||||||
context_passed_along_steps:
|
context_passed_along_steps:
|
||||||
)
|
)
|
||||||
expected_rop_steps = []
|
expected_rop_steps = []
|
||||||
|
skip_unless_inspect = false
|
||||||
|
|
||||||
rop_steps.each do |rop_step|
|
rop_steps.each do |rop_step|
|
||||||
step_class = rop_step[0]
|
step_class = rop_step[0]
|
||||||
|
|
@ -121,13 +122,11 @@ module InvokeRopSteps
|
||||||
step_action: step_action
|
step_action: step_action
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next if skip_unless_inspect && [:inspect_ok, :inspect_err].freeze.exclude?(step_action)
|
||||||
|
|
||||||
if err_results_for_steps.key?(step_class)
|
if err_results_for_steps.key?(step_class)
|
||||||
expected_rop_step[:returned_object] = err_results_for_steps[step_class]
|
expected_rop_step[:returned_object] = err_results_for_steps[step_class]
|
||||||
|
skip_unless_inspect = true
|
||||||
# Currently, only a single error step is supported, so we assign expected_rop_step as the last entry
|
|
||||||
# in expected_rop_steps, break out of the loop early, and do not add any more steps
|
|
||||||
expected_rop_steps << expected_rop_step
|
|
||||||
break
|
|
||||||
elsif ok_results_for_steps.key?(step_class)
|
elsif ok_results_for_steps.key?(step_class)
|
||||||
expected_rop_step[:returned_object] = ok_results_for_steps[step_class]
|
expected_rop_step[:returned_object] = ok_results_for_steps[step_class]
|
||||||
elsif step_action == :and_then
|
elsif step_action == :and_then
|
||||||
|
|
@ -169,7 +168,9 @@ module InvokeRopSteps
|
||||||
context_passed_along_steps:,
|
context_passed_along_steps:,
|
||||||
returned_object:
|
returned_object:
|
||||||
)
|
)
|
||||||
expect(step_class).to receive(step_class_method).with(context_passed_along_steps).ordered do
|
expectation = expect(step_class).to receive(step_class_method)
|
||||||
|
expectation = expectation.with(context_passed_along_steps) if step_class_method != :observe
|
||||||
|
expectation.ordered do
|
||||||
returned_object
|
returned_object
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -64,38 +64,21 @@ RSpec.shared_examples 'work item drawer' do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when in notifications subscription' do
|
context 'when in notifications subscription' do
|
||||||
before do
|
|
||||||
within_testid('work-item-drawer') do
|
|
||||||
find_by_testid('work-item-actions-dropdown').click
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'displays notifications toggle', :aggregate_failures do
|
|
||||||
within_testid('work-item-drawer') do
|
|
||||||
expect(page).to have_selector('[data-testid="notifications-toggle-form"]')
|
|
||||||
expect(page).to have_content('Notifications')
|
|
||||||
expect(page).not_to have_content('Disabled by project owner')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'shows toggle as on then as off as user toggles to subscribe and unsubscribe', :aggregate_failures do
|
it 'shows toggle as on then as off as user toggles to subscribe and unsubscribe', :aggregate_failures do
|
||||||
within_testid('notifications-toggle-form') do
|
subscribe_button = find_by_testid('subscribe-button')
|
||||||
subscription_button = find('[data-testid="notifications-toggle"] button')
|
expect(page).to have_selector("button[data-testid='subscribe-button'][data-subscribed='false']")
|
||||||
|
|
||||||
expect(page).not_to have_css("button.is-checked")
|
subscribe_button.click
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
subscription_button.click
|
expect(page).to have_content("Notifications turned on.")
|
||||||
|
expect(page).to have_selector("button[data-testid='subscribe-button'][data-subscribed='true']")
|
||||||
|
|
||||||
wait_for_requests
|
subscribe_button.click
|
||||||
|
wait_for_requests
|
||||||
|
|
||||||
expect(page).to have_css("button.is-checked")
|
expect(page).to have_content("Notifications turned off.")
|
||||||
|
expect(page).to have_selector("button[data-testid='subscribe-button'][data-subscribed='false']")
|
||||||
subscription_button.click
|
|
||||||
|
|
||||||
wait_for_requests
|
|
||||||
|
|
||||||
expect(page).not_to have_css("button.is-checked")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue