diff --git a/.eslint_todo/index.mjs b/.eslint_todo/index.mjs new file mode 100644 index 0000000000000000000000000000000000000000..88c73e337a5011534c1e5261b41a6168b5d5b27a --- /dev/null +++ b/.eslint_todo/index.mjs @@ -0,0 +1 @@ +export { default as vueNoUnusedProperties } from './vue-no-unused-properties.mjs'; diff --git a/.eslint_todo/vue-no-unused-properties.mjs b/.eslint_todo/vue-no-unused-properties.mjs new file mode 100644 index 0000000000000000000000000000000000000000..3bb95b243ece805ac13b922a86b390e5714758fe --- /dev/null +++ b/.eslint_todo/vue-no-unused-properties.mjs @@ -0,0 +1,640 @@ +/** + * Generated by `scripts/frontend/generate_eslint_todo_list.mjs`. + */ +export default { + files: [ + 'app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue', + 'app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_comment_form.vue', + 'app/assets/javascripts/admin/abuse_report/components/notes/abuse_report_edit_note.vue', + 'app/assets/javascripts/admin/statistics_panel/components/app.vue', + 'app/assets/javascripts/alerts_settings/components/alerts_integrations_list.vue', + 'app/assets/javascripts/analytics/cycle_analytics/components/base.vue', + 'app/assets/javascripts/analytics/shared/components/projects_dropdown_filter.vue', + 'app/assets/javascripts/analytics/usage_trends/components/users_chart.vue', + 'app/assets/javascripts/badges/components/badge.vue', + 'app/assets/javascripts/badges/components/badge_form.vue', + 'app/assets/javascripts/batch_comments/components/draft_note.vue', + 'app/assets/javascripts/batch_comments/components/preview_item.vue', + 'app/assets/javascripts/behaviors/components/json_table.vue', + 'app/assets/javascripts/behaviors/components/sandboxed_mermaid.vue', + 'app/assets/javascripts/behaviors/shortcuts/shortcut.vue', + 'app/assets/javascripts/blame/preferences/blame_preferences.vue', + 'app/assets/javascripts/blob/filepath_form/components/template_selector.vue', + 'app/assets/javascripts/boards/components/board_add_new_column_form.vue', + 'app/assets/javascripts/boards/components/board_card_inner.vue', + 'app/assets/javascripts/boards/components/board_card_move_to_position.vue', + 'app/assets/javascripts/boards/components/board_content.vue', + 'app/assets/javascripts/boards/components/board_filtered_search.vue', + 'app/assets/javascripts/boards/components/board_list_header.vue', + 'app/assets/javascripts/boards/components/board_settings_sidebar.vue', + 'app/assets/javascripts/boards/components/boards_selector.vue', + 'app/assets/javascripts/boards/components/issue_due_date.vue', + 'app/assets/javascripts/boards/components/project_select.vue', + 'app/assets/javascripts/ci/artifacts/components/job_artifacts_table.vue', + 'app/assets/javascripts/ci/catalog/components/list/ci_resources_list.vue', + 'app/assets/javascripts/ci/catalog/components/pages/ci_resources_page.vue', + 'app/assets/javascripts/ci/job_details/components/job_header.vue', + 'app/assets/javascripts/ci/job_details/components/log/log.vue', + 'app/assets/javascripts/ci/job_details/components/manual_variables_form.vue', + 'app/assets/javascripts/ci/jobs_page/components/job_cells/actions_cell.vue', + 'app/assets/javascripts/ci/jobs_page/components/job_cells/status_cell.vue', + 'app/assets/javascripts/ci/merge_requests/components/pipelines_table_wrapper.vue', + 'app/assets/javascripts/ci/pipeline_details/graph/components/job_item.vue', + 'app/assets/javascripts/ci/pipeline_details/graph/components/linked_pipeline.vue', + 'app/assets/javascripts/ci/pipeline_details/graph/components/links_inner.vue', + 'app/assets/javascripts/ci/pipeline_details/graph/components/root_graph_layout.vue', + 'app/assets/javascripts/ci/pipeline_details/graph/components/stage_column_component.vue', + 'app/assets/javascripts/ci/pipeline_details/header/pipeline_header.vue', + 'app/assets/javascripts/ci/pipeline_details/manual_variables/variable_table.vue', + 'app/assets/javascripts/ci/pipeline_editor/components/commit/commit_section.vue', + 'app/assets/javascripts/ci/pipeline_editor/components/editor/ci_config_merged_preview.vue', + 'app/assets/javascripts/ci/pipeline_editor/components/file_nav/branch_switcher.vue', + 'app/assets/javascripts/ci/pipeline_editor/components/graph/job_pill.vue', + 'app/assets/javascripts/ci/pipeline_editor/components/graph/pipeline_graph.vue', + 'app/assets/javascripts/ci/pipeline_editor/components/pipeline_editor_tabs.vue', + 'app/assets/javascripts/ci/pipeline_editor/components/popovers/validate_pipeline_popover.vue', + 'app/assets/javascripts/ci/pipeline_editor/pipeline_editor_app.vue', + 'app/assets/javascripts/ci/pipeline_new/components/pipeline_new_form.vue', + 'app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue', + 'app/assets/javascripts/ci/pipelines_page/components/failure_widget/failed_job_details.vue', + 'app/assets/javascripts/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue', + 'app/assets/javascripts/ci/pipelines_page/components/pipelines_artifacts.vue', + 'app/assets/javascripts/ci/pipelines_page/pipelines.vue', + 'app/assets/javascripts/ci/reports/components/report_section.vue', + 'app/assets/javascripts/ci/runner/admin_runner_show/admin_runner_show_app.vue', + 'app/assets/javascripts/ci/runner/components/cells/runner_summary_cell.vue', + 'app/assets/javascripts/ci/runner/components/registration/registration_dropdown.vue', + 'app/assets/javascripts/ci/runner/components/registration/runner_instructions/runner_instructions_modal.vue', + 'app/assets/javascripts/ci/runner/components/runner_delete_button.vue', + 'app/assets/javascripts/ci/runner/components/runner_delete_modal.vue', + 'app/assets/javascripts/ci/runner/components/runner_pause_action.vue', + 'app/assets/javascripts/ci/runner/components/runner_type_tabs.vue', + 'app/assets/javascripts/ci/runner/components/stat/runner_count.vue', + 'app/assets/javascripts/ci/runner/group_new_runner/group_new_runner_app.vue', + 'app/assets/javascripts/ci/runner/group_runner_show/group_runner_show_app.vue', + 'app/assets/javascripts/ci/runner/project_new_runner/project_new_runner_app.vue', + 'app/assets/javascripts/clusters_list/components/agents.vue', + 'app/assets/javascripts/clusters_list/components/delete_agent_button.vue', + 'app/assets/javascripts/clusters_list/components/install_agent_modal.vue', + 'app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue', + 'app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue', + 'app/assets/javascripts/content_editor/components/content_editor.vue', + 'app/assets/javascripts/content_editor/components/suggestions_dropdown.vue', + 'app/assets/javascripts/content_editor/components/toolbar_attachment_button.vue', + 'app/assets/javascripts/content_editor/components/toolbar_text_style_dropdown.vue', + 'app/assets/javascripts/content_editor/components/wrappers/code_block.vue', + 'app/assets/javascripts/content_editor/components/wrappers/details.vue', + 'app/assets/javascripts/content_editor/components/wrappers/paragraph.vue', + 'app/assets/javascripts/content_editor/components/wrappers/table_of_contents.vue', + 'app/assets/javascripts/contribution_events/components/contribution_event/contribution_event_closed.vue', + 'app/assets/javascripts/contributors/components/contributors.vue', + 'app/assets/javascripts/custom_emoji/pages/index.vue', + 'app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue', + 'app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue', + 'app/assets/javascripts/deployments/components/deployment_header.vue', + 'app/assets/javascripts/design_management/components/design_description/description_form.vue', + 'app/assets/javascripts/design_management/components/design_notes/design_discussion.vue', + 'app/assets/javascripts/design_management/components/design_notes/design_note.vue', + 'app/assets/javascripts/design_management/components/design_sidebar.vue', + 'app/assets/javascripts/design_management/pages/index.vue', + 'app/assets/javascripts/diffs/components/app.vue', + 'app/assets/javascripts/diffs/components/diff_content.vue', + 'app/assets/javascripts/diffs/components/diff_expansion_cell.vue', + 'app/assets/javascripts/diffs/components/diff_file.vue', + 'app/assets/javascripts/diffs/components/diff_file_header.vue', + 'app/assets/javascripts/diffs/components/diff_line_note_form.vue', + 'app/assets/javascripts/diffs/components/diff_row.vue', + 'app/assets/javascripts/diffs/components/diff_view.vue', + 'app/assets/javascripts/diffs/components/image_diff_overlay.vue', + 'app/assets/javascripts/emoji/components/picker.vue', + 'app/assets/javascripts/environments/components/canary_update_modal.vue', + 'app/assets/javascripts/environments/components/deployment.vue', + 'app/assets/javascripts/environments/components/empty_state.vue', + 'app/assets/javascripts/environments/components/enable_review_app_modal.vue', + 'app/assets/javascripts/environments/components/environment_flux_resource_selector.vue', + 'app/assets/javascripts/environments/components/environment_form.vue', + 'app/assets/javascripts/environments/components/environment_item.vue', + 'app/assets/javascripts/environments/environment_details/components/deployment_actions.vue', + 'app/assets/javascripts/environments/environment_details/components/deployment_history.vue', + 'app/assets/javascripts/environments/environment_details/components/kubernetes/kubernetes_overview.vue', + 'app/assets/javascripts/environments/folder/environments_folder_view.vue', + 'app/assets/javascripts/error_tracking/components/error_details.vue', + 'app/assets/javascripts/error_tracking/components/error_tracking_list.vue', + 'app/assets/javascripts/error_tracking_settings/components/project_dropdown.vue', + 'app/assets/javascripts/feature_flags/components/empty_state.vue', + 'app/assets/javascripts/feature_flags/components/environments_dropdown.vue', + 'app/assets/javascripts/feature_flags/components/feature_flags.vue', + 'app/assets/javascripts/feature_flags/components/feature_flags_table.vue', + 'app/assets/javascripts/feature_flags/components/form.vue', + 'app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue', + 'app/assets/javascripts/gitlab_pages/components/deployment.vue', + 'app/assets/javascripts/gitlab_pages/components/deployments.vue', + 'app/assets/javascripts/google_cloud/gcp_regions/list.vue', + 'app/assets/javascripts/groups/components/group_item.vue', + 'app/assets/javascripts/groups/components/invite_members_banner.vue', + 'app/assets/javascripts/ide/components/commit_sidebar/form.vue', + 'app/assets/javascripts/ide/components/commit_sidebar/list_item.vue', + 'app/assets/javascripts/ide/components/commit_sidebar/radio_group.vue', + 'app/assets/javascripts/ide/components/file_row_extra.vue', + 'app/assets/javascripts/ide/components/ide.vue', + 'app/assets/javascripts/ide/components/ide_side_bar.vue', + 'app/assets/javascripts/ide/components/ide_status_bar.vue', + 'app/assets/javascripts/ide/components/ide_tree.vue', + 'app/assets/javascripts/ide/components/ide_tree_list.vue', + 'app/assets/javascripts/ide/components/jobs/item.vue', + 'app/assets/javascripts/ide/components/merge_requests/list.vue', + 'app/assets/javascripts/ide/components/new_dropdown/modal.vue', + 'app/assets/javascripts/ide/components/panes/right.vue', + 'app/assets/javascripts/ide/components/pipelines/list.vue', + 'app/assets/javascripts/ide/components/repo_commit_section.vue', + 'app/assets/javascripts/ide/components/repo_editor.vue', + 'app/assets/javascripts/ide/components/repo_tabs.vue', + 'app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue', + 'app/assets/javascripts/import_entities/import_groups/components/import_table.vue', + 'app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue', + 'app/assets/javascripts/import_entities/import_projects/components/github_status_table.vue', + 'app/assets/javascripts/integrations/beyond_identity/components/exclusions_list.vue', + 'app/assets/javascripts/integrations/edit/components/integration_form_actions.vue', + 'app/assets/javascripts/invite_members/components/group_select.vue', + 'app/assets/javascripts/invite_members/components/invite_group_notification.vue', + 'app/assets/javascripts/invite_members/components/project_select.vue', + 'app/assets/javascripts/invite_members/components/user_limit_notification.vue', + 'app/assets/javascripts/issuable/components/csv_import_export_buttons.vue', + 'app/assets/javascripts/issuable/popover/components/comment_popover.vue', + 'app/assets/javascripts/issues/list/components/empty_state_without_any_issues.vue', + 'app/assets/javascripts/issues/list/components/issue_card_time_info.vue', + 'app/assets/javascripts/issues/list/components/jira_issues_import_status_app.vue', + 'app/assets/javascripts/issues/show/components/description.vue', + 'app/assets/javascripts/issues/show/components/edit_actions.vue', + 'app/assets/javascripts/issues/show/components/fields/description.vue', + 'app/assets/javascripts/issues/show/components/fields/type.vue', + 'app/assets/javascripts/issues/show/components/header_actions.vue', + 'app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue', + 'app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue', + 'app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue', + 'app/assets/javascripts/issues/show/components/sentry_error_stack_trace.vue', + 'app/assets/javascripts/issues/show/components/title.vue', + 'app/assets/javascripts/jira_connect/branches/components/new_branch_form.vue', + 'app/assets/javascripts/jira_import/components/jira_import_form.vue', + 'app/assets/javascripts/kubernetes_dashboard/components/workload_details.vue', + 'app/assets/javascripts/kubernetes_dashboard/components/workload_details_drawer.vue', + 'app/assets/javascripts/members/components/filter_sort/sort_dropdown.vue', + 'app/assets/javascripts/members/placeholders/components/csv_upload_modal.vue', + 'app/assets/javascripts/merge_request_dashboard/components/status_badge.vue', + 'app/assets/javascripts/merge_requests/components/reviewers/reviewer_drawer.vue', + 'app/assets/javascripts/milestones/components/delete_milestone_modal.vue', + 'app/assets/javascripts/milestones/components/more_actions_dropdown.vue', + 'app/assets/javascripts/ml/experiment_tracking/components/candidate_list.vue', + 'app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue', + 'app/assets/javascripts/ml/experiment_tracking/routes/candidates/promote/model_selection_dropdown.vue', + 'app/assets/javascripts/ml/experiment_tracking/routes/candidates/show/candidate_detail.vue', + 'app/assets/javascripts/ml/model_registry/apps/show_ml_model.vue', + 'app/assets/javascripts/ml/model_registry/components/candidate_list.vue', + 'app/assets/javascripts/ml/model_registry/components/delete_model_disclosure_dropdown_item.vue', + 'app/assets/javascripts/ml/model_registry/components/model_detail.vue', + 'app/assets/javascripts/ml/model_registry/components/model_edit.vue', + 'app/assets/javascripts/notebook/cells/output/error.vue', + 'app/assets/javascripts/notebook/cells/prompt.vue', + 'app/assets/javascripts/notes/components/comment_form.vue', + 'app/assets/javascripts/notes/components/comment_type_dropdown.vue', + 'app/assets/javascripts/notes/components/diff_discussion_header.vue', + 'app/assets/javascripts/notes/components/discussion_actions.vue', + 'app/assets/javascripts/notes/components/discussion_counter.vue', + 'app/assets/javascripts/notes/components/discussion_filter.vue', + 'app/assets/javascripts/notes/components/multiline_comment_form.vue', + 'app/assets/javascripts/notes/components/note_actions.vue', + 'app/assets/javascripts/notes/components/note_awards_list.vue', + 'app/assets/javascripts/notes/components/note_header.vue', + 'app/assets/javascripts/notes/components/noteable_discussion.vue', + 'app/assets/javascripts/notes/components/noteable_note.vue', + 'app/assets/javascripts/notes/components/notes_app.vue', + 'app/assets/javascripts/notifications/components/custom_notifications_modal.vue', + 'app/assets/javascripts/organizations/groups_and_projects/components/app.vue', + 'app/assets/javascripts/organizations/shared/components/new_edit_form.vue', + 'app/assets/javascripts/packages_and_registries/container_registry/explorer/components/delete_modal.vue', + 'app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue', + 'app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/registry_header.vue', + 'app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue', + 'app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue', + 'app/assets/javascripts/packages_and_registries/harbor_registry/components/details/artifacts_list.vue', + 'app/assets/javascripts/packages_and_registries/harbor_registry/pages/details.vue', + 'app/assets/javascripts/packages_and_registries/harbor_registry/pages/list.vue', + 'app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/app.vue', + 'app/assets/javascripts/packages_and_registries/infrastructure_registry/details/components/package_history.vue', + 'app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list.vue', + 'app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/components/delete_modal.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/components/details/file_sha.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/components/details/package_files.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/components/details/package_history.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/components/details/package_versions_list.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/components/list/package_list_row.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/components/list/package_title.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/components/list/packages_list.vue', + 'app/assets/javascripts/packages_and_registries/package_registry/pages/details.vue', + 'app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy_form.vue', + 'app/assets/javascripts/packages_and_registries/settings/project/components/container_protection_repository_rules.vue', + 'app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue', + 'app/assets/javascripts/packages_and_registries/settings/project/components/packages_protection_rules.vue', + 'app/assets/javascripts/packages_and_registries/shared/components/delete_package_modal.vue', + 'app/assets/javascripts/pages/projects/pipeline_schedules/shared/components/interval_pattern_input.vue', + 'app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue', + 'app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue', + 'app/assets/javascripts/pages/shared/wikis/components/wiki_form.vue', + 'app/assets/javascripts/pages/shared/wikis/wiki_notes/components/placeholder_note.vue', + 'app/assets/javascripts/pages/shared/wikis/wiki_notes/components/wiki_discussion.vue', + 'app/assets/javascripts/pages/shared/wikis/wiki_notes/components/wiki_notes_app.vue', + 'app/assets/javascripts/performance_bar/components/performance_bar_app.vue', + 'app/assets/javascripts/pipeline_wizard/components/widgets/checklist.vue', + 'app/assets/javascripts/pipeline_wizard/components/widgets/list.vue', + 'app/assets/javascripts/pipeline_wizard/components/wrapper.vue', + 'app/assets/javascripts/popovers/components/popovers.vue', + 'app/assets/javascripts/projects/commit/components/form_modal.vue', + 'app/assets/javascripts/projects/commit/components/projects_dropdown.vue', + 'app/assets/javascripts/projects/filtered_search_and_sort/components/filtered_search_and_sort.vue', + 'app/assets/javascripts/projects/new_v2/components/app.vue', + 'app/assets/javascripts/projects/new_v2/components/project_destination_select.vue', + 'app/assets/javascripts/projects/pipelines/charts/components/statistics_list.vue', + 'app/assets/javascripts/projects/settings/branch_rules/components/edit/protections/merge_protections.vue', + 'app/assets/javascripts/projects/settings/branch_rules/components/edit/protections/push_protections.vue', + 'app/assets/javascripts/projects/settings/components/branch_rule_modal.vue', + 'app/assets/javascripts/projects/settings/repository/branch_rules/app.vue', + 'app/assets/javascripts/projects/settings_service_desk/components/custom_email_form.vue', + 'app/assets/javascripts/projects/settings_service_desk/components/service_desk_setting.vue', + 'app/assets/javascripts/ref/components/ref_selector.vue', + 'app/assets/javascripts/releases/components/app_edit_new.vue', + 'app/assets/javascripts/releases/components/tag_field_new.vue', + 'app/assets/javascripts/releases/components/tag_search.vue', + 'app/assets/javascripts/repository/components/blob_content_viewer.vue', + 'app/assets/javascripts/repository/components/blob_viewers/geo_json/geo_json_viewer.vue', + 'app/assets/javascripts/repository/components/commit_changes_modal.vue', + 'app/assets/javascripts/repository/components/delete_blob_modal.vue', + 'app/assets/javascripts/repository/components/fork_sync_conflicts_modal.vue', + 'app/assets/javascripts/repository/components/header_area/blob_controls.vue', + 'app/assets/javascripts/repository/components/table/row.vue', + 'app/assets/javascripts/repository/components/tree_content.vue', + 'app/assets/javascripts/repository/components/upload_blob_modal.vue', + 'app/assets/javascripts/repository/pages/blob_edit_header.vue', + 'app/assets/javascripts/search/results/components/blob_body.vue', + 'app/assets/javascripts/search/results/components/status_bar.vue', + 'app/assets/javascripts/search/sidebar/components/group_filter.vue', + 'app/assets/javascripts/search/sidebar/components/project_filter.vue', + 'app/assets/javascripts/search/sidebar/components/scope_sidebar_navigation.vue', + 'app/assets/javascripts/search/topbar/components/app.vue', + 'app/assets/javascripts/security_configuration/components/secret_push_protection_feature_card.vue', + 'app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue', + 'app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue', + 'app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue', + 'app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue', + 'app/assets/javascripts/sidebar/components/incidents/escalation_status.vue', + 'app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue', + 'app/assets/javascripts/sidebar/components/labels/labels_select_vue/dropdown_contents_labels_view.vue', + 'app/assets/javascripts/sidebar/components/labels/labels_select_vue/dropdown_title.vue', + 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents.vue', + 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue', + 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_header.vue', + 'app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue', + 'app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue', + 'app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue', + 'app/assets/javascripts/sidebar/components/reviewers/reviewer_avatar_link.vue', + 'app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue', + 'app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue', + 'app/assets/javascripts/sidebar/components/sidebar_dropdown.vue', + 'app/assets/javascripts/sidebar/components/status/status_dropdown.vue', + 'app/assets/javascripts/sidebar/components/subscriptions/subscriptions.vue', + 'app/assets/javascripts/stars/components/star_count.vue', + 'app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_overview_dropdown.vue', + 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search.vue', + 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search_autocomplete_items.vue', + 'app/assets/javascripts/super_sidebar/components/global_search/components/global_search_scoped_items.vue', + 'app/assets/javascripts/super_sidebar/components/help_center.vue', + 'app/assets/javascripts/super_sidebar/components/pinned_section.vue', + 'app/assets/javascripts/super_sidebar/components/super_sidebar.vue', + 'app/assets/javascripts/tags/components/delete_tag_modal.vue', + 'app/assets/javascripts/todos/components/snooze_todo_modal.vue', + 'app/assets/javascripts/todos/components/todo_item_actions.vue', + 'app/assets/javascripts/todos/components/todo_item_timestamp.vue', + 'app/assets/javascripts/todos/components/todos_app.vue', + 'app/assets/javascripts/token_access/components/outbound_token_access.vue', + 'app/assets/javascripts/token_access/components/token_permissions.vue', + 'app/assets/javascripts/tooltips/components/tooltips.vue', + 'app/assets/javascripts/usage_quotas/components/search_and_sort_bar/search_and_sort_bar.vue', + 'app/assets/javascripts/user_lists/components/user_lists.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/approvals/approvals.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/checks/message.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_actions.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_how_to_merge_modal.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_migrate_jenkins.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_pipeline_container.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/state_container.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_archived.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_checking.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue', + 'app/assets/javascripts/vue_merge_request_widget/components/widget/action_buttons.vue', + 'app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue', + 'app/assets/javascripts/vue_merge_request_widget/widgets/accessibility/index.vue', + 'app/assets/javascripts/vue_merge_request_widget/widgets/code_quality/index.vue', + 'app/assets/javascripts/vue_shared/alert_details/components/sidebar/sidebar_assignee.vue', + 'app/assets/javascripts/vue_shared/alert_details/components/sidebar/sidebar_status.vue', + 'app/assets/javascripts/vue_shared/components/awards_list.vue', + 'app/assets/javascripts/vue_shared/components/badges/beta_badge.vue', + 'app/assets/javascripts/vue_shared/components/color_select_dropdown/dropdown_contents.vue', + 'app/assets/javascripts/vue_shared/components/crud_component.vue', + 'app/assets/javascripts/vue_shared/components/customizable_dashboard/customizable_dashboard.vue', + 'app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue', + 'app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue', + 'app/assets/javascripts/vue_shared/components/entity_select/entity_select.vue', + 'app/assets/javascripts/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue', + 'app/assets/javascripts/vue_shared/components/groups_list/group_list_item_prevent_delete_modal.vue', + 'app/assets/javascripts/vue_shared/components/list_selector/index.vue', + 'app/assets/javascripts/vue_shared/components/markdown/comment_templates_modal.vue', + 'app/assets/javascripts/vue_shared/components/markdown/field.vue', + 'app/assets/javascripts/vue_shared/components/markdown/header.vue', + 'app/assets/javascripts/vue_shared/components/markdown/markdown_editor.vue', + 'app/assets/javascripts/vue_shared/components/markdown/toolbar.vue', + 'app/assets/javascripts/vue_shared/components/markdown_drawer/markdown_drawer.vue', + 'app/assets/javascripts/vue_shared/components/mr_more_dropdown.vue', + 'app/assets/javascripts/vue_shared/components/new_resource_dropdown/new_resource_dropdown.vue', + 'app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue', + 'app/assets/javascripts/vue_shared/components/notes/system_note.vue', + 'app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue', + 'app/assets/javascripts/vue_shared/components/registry/list_item.vue', + 'app/assets/javascripts/vue_shared/components/smart_virtual_list.vue', + 'app/assets/javascripts/vue_shared/components/source_editor.vue', + 'app/assets/javascripts/vue_shared/components/source_viewer/components/chunk.vue', + 'app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue', + 'app/assets/javascripts/vue_shared/components/user_select/user_select.vue', + 'app/assets/javascripts/vue_shared/issuable/list/components/issuable_item.vue', + 'app/assets/javascripts/vue_shared/issuable/list/components/issuable_list_root.vue', + 'app/assets/javascripts/vue_shared/issuable/show/components/issuable_header.vue', + 'app/assets/javascripts/webhooks/components/form_custom_header_item.vue', + 'app/assets/javascripts/work_items/components/create_work_item.vue', + 'app/assets/javascripts/work_items/components/design_management/design_notes/design_discussion.vue', + 'app/assets/javascripts/work_items/components/notes/system_note.vue', + 'app/assets/javascripts/work_items/components/notes/work_item_activity_sort_filter.vue', + 'app/assets/javascripts/work_items/components/notes/work_item_add_note.vue', + 'app/assets/javascripts/work_items/components/notes/work_item_comment_locked.vue', + 'app/assets/javascripts/work_items/components/notes/work_item_note.vue', + 'app/assets/javascripts/work_items/components/notes/work_item_note_actions.vue', + 'app/assets/javascripts/work_items/components/notes/work_item_note_awards_list.vue', + 'app/assets/javascripts/work_items/components/notes/work_item_note_body.vue', + 'app/assets/javascripts/work_items/components/shared/work_item_link_child_metadata.vue', + 'app/assets/javascripts/work_items/components/shared/work_item_token_input.vue', + 'app/assets/javascripts/work_items/components/work_item_actions.vue', + 'app/assets/javascripts/work_items/components/work_item_assignees.vue', + 'app/assets/javascripts/work_items/components/work_item_attributes_wrapper.vue', + 'app/assets/javascripts/work_items/components/work_item_change_type_modal.vue', + 'app/assets/javascripts/work_items/components/work_item_crm_contacts.vue', + 'app/assets/javascripts/work_items/components/work_item_description.vue', + 'app/assets/javascripts/work_items/components/work_item_detail.vue', + 'app/assets/javascripts/work_items/components/work_item_detail_modal.vue', + 'app/assets/javascripts/work_items/components/work_item_development/work_item_create_branch_merge_request_modal.vue', + 'app/assets/javascripts/work_items/components/work_item_development/work_item_development.vue', + 'app/assets/javascripts/work_items/components/work_item_development/work_item_development_mr_item.vue', + 'app/assets/javascripts/work_items/components/work_item_due_date.vue', + 'app/assets/javascripts/work_items/components/work_item_labels.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_children_wrapper.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_groups_listbox.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_link_child.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_links.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_links_form.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_projects_listbox.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_rolled_up_count.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_rolled_up_data.vue', + 'app/assets/javascripts/work_items/components/work_item_links/work_item_tree.vue', + 'app/assets/javascripts/work_items/components/work_item_milestone.vue', + 'app/assets/javascripts/work_items/components/work_item_notes.vue', + 'app/assets/javascripts/work_items/components/work_item_notifications_widget.vue', + 'app/assets/javascripts/work_items/components/work_item_relationships/work_item_relationship_list.vue', + 'app/assets/javascripts/work_items/components/work_item_state_toggle.vue', + 'app/assets/javascripts/work_items/components/work_item_sticky_header.vue', + 'ee/app/assets/javascripts/admin/subscriptions/show/components/subscription_breakdown.vue', + 'ee/app/assets/javascripts/ai/components/duo_chat_feedback_modal.vue', + 'ee/app/assets/javascripts/ai/components/user_feedback.vue', + 'ee/app/assets/javascripts/analytics/analytics_dashboards/components/analytics_dashboard_panel.vue', + 'ee/app/assets/javascripts/analytics/analytics_dashboards/components/dashboards_list.vue', + 'ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualizations/data_table.vue', + 'ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualizations/dora_chart.vue', + 'ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualizations/dora_performers_score.vue', + 'ee/app/assets/javascripts/analytics/analytics_dashboards/components/visualizations/usage_overview.vue', + 'ee/app/assets/javascripts/analytics/cycle_analytics/components/base.vue', + 'ee/app/assets/javascripts/analytics/cycle_analytics/components/value_stream_select.vue', + 'ee/app/assets/javascripts/analytics/cycle_analytics/vsa_settings/components/value_stream_form_content.vue', + 'ee/app/assets/javascripts/analytics/devops_reports/devops_adoption/components/devops_adoption_add_dropdown.vue', + 'ee/app/assets/javascripts/analytics/devops_reports/devops_adoption/components/devops_adoption_app.vue', + 'ee/app/assets/javascripts/analytics/devops_reports/devops_adoption/components/devops_adoption_table_cell_flag.vue', + 'ee/app/assets/javascripts/analytics/productivity_analytics/components/app.vue', + 'ee/app/assets/javascripts/analytics/repository_analytics/components/test_coverage_summary.vue', + 'ee/app/assets/javascripts/analytics/repository_analytics/components/test_coverage_table.vue', + 'ee/app/assets/javascripts/approvals/components/approval_settings/approval_settings_locked_icon.vue', + 'ee/app/assets/javascripts/approvals/components/rule_modal/remove_rule.vue', + 'ee/app/assets/javascripts/approvals/components/rules/rule_controls.vue', + 'ee/app/assets/javascripts/approvals/components/rules/rule_form.vue', + 'ee/app/assets/javascripts/approvals/mr_edit/app.vue', + 'ee/app/assets/javascripts/approvals/project_settings/project_rules.vue', + 'ee/app/assets/javascripts/audit_events/components/audit_events_stream.vue', + 'ee/app/assets/javascripts/audit_events/components/stream/stream_delete_modal.vue', + 'ee/app/assets/javascripts/audit_events/components/stream/stream_destination_editor.vue', + 'ee/app/assets/javascripts/billings/components/zuora_simple.vue', + 'ee/app/assets/javascripts/billings/subscriptions/components/subscription_table.vue', + 'ee/app/assets/javascripts/boards/components/board_form.vue', + 'ee/app/assets/javascripts/boards/components/board_list_header.vue', + 'ee/app/assets/javascripts/boards/components/board_new_issue.vue', + 'ee/app/assets/javascripts/boards/components/board_scope.vue', + 'ee/app/assets/javascripts/boards/components/boards_selector.vue', + 'ee/app/assets/javascripts/boards/components/epics_swimlanes.vue', + 'ee/app/assets/javascripts/boards/components/group_select.vue', + 'ee/app/assets/javascripts/boards/components/issue_board_filtered_search.vue', + 'ee/app/assets/javascripts/burndown_chart/components/burn_charts.vue', + 'ee/app/assets/javascripts/burndown_chart/components/open_timebox_summary.vue', + 'ee/app/assets/javascripts/ci/job_details/components/job_log_top_bar.vue', + 'ee/app/assets/javascripts/ci/merge_trains/components/merge_trains_table.vue', + 'ee/app/assets/javascripts/ci/runner/components/shared_runner_limit_block.vue', + 'ee/app/assets/javascripts/ci/secrets/components/secret_details/secret_details.vue', + 'ee/app/assets/javascripts/ci/secrets/components/secret_details/secret_details_wrapper.vue', + 'ee/app/assets/javascripts/ci/secrets/components/secret_form/secret_form.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/frameworks_report/edit_framework/components/delete_modal.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/frameworks_report/edit_framework/components/requirement_modal.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/frameworks_report/framework_info_drawer.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/frameworks_report/frameworks_table.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/projects_report/projects_table.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/projects_report/selection_operations.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/shared/framework_badge.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/shared/pagination.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/standards_adherence_report/base_table.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/violations_report/drawer_sections/reviewers.vue', + 'ee/app/assets/javascripts/compliance_dashboard/components/violations_report/report.vue', + 'ee/app/assets/javascripts/dependencies/components/app.vue', + 'ee/app/assets/javascripts/dependencies/components/dependency_project_count.vue', + 'ee/app/assets/javascripts/dependencies/components/filtered_search/dependencies_filtered_search.vue', + 'ee/app/assets/javascripts/environments_dashboard/components/dashboard/dashboard.vue', + 'ee/app/assets/javascripts/environments_dashboard/components/dashboard/environment.vue', + 'ee/app/assets/javascripts/epic/components/epic_header.vue', + 'ee/app/assets/javascripts/external_issues_show/components/note.vue', + 'ee/app/assets/javascripts/geo_sites/components/header/geo_site_last_updated.vue', + 'ee/app/assets/javascripts/groups/settings/compliance_frameworks/components/form_modal.vue', + 'ee/app/assets/javascripts/hand_raise_leads/hand_raise_lead/components/hand_raise_lead_button.vue', + 'ee/app/assets/javascripts/hand_raise_leads/hand_raise_lead/components/hand_raise_lead_modal.vue', + 'ee/app/assets/javascripts/insights/components/insights_chart.vue', + 'ee/app/assets/javascripts/integrations/edit/components/google_artifact_management/configuration_instructions.vue', + 'ee/app/assets/javascripts/integrations/edit/components/jira_issue_creation_vulnerabilities.vue', + 'ee/app/assets/javascripts/integrations/zentao/issues_show/components/sidebar/zentao_issues_sidebar_root.vue', + 'ee/app/assets/javascripts/invite_members/components/invite_modal_base.vue', + 'ee/app/assets/javascripts/issues/components/related_feature_flags.vue', + 'ee/app/assets/javascripts/iterations/components/iteration_cadence_list_item.vue', + 'ee/app/assets/javascripts/iterations/components/iteration_form.vue', + 'ee/app/assets/javascripts/iterations/components/iteration_report.vue', + 'ee/app/assets/javascripts/linked_resources/components/resource_links_block.vue', + 'ee/app/assets/javascripts/logs/list/related_issues/related_issues_provider.vue', + 'ee/app/assets/javascripts/members/promotion_requests/components/app.vue', + 'ee/app/assets/javascripts/merge_requests/components/reviewers/approval_summary.vue', + 'ee/app/assets/javascripts/metrics/details/metrics_details.vue', + 'ee/app/assets/javascripts/metrics/details/metrics_line_chart.vue', + 'ee/app/assets/javascripts/metrics/details/related_issues/related_issues_provider.vue', + 'ee/app/assets/javascripts/ml/ai_agents/components/agent_list.vue', + 'ee/app/assets/javascripts/ml/ai_agents/views/list_agents.vue', + 'ee/app/assets/javascripts/notes/components/ai_summary.vue', + 'ee/app/assets/javascripts/notes/components/note_actions/ai_summarize_notes.vue', + 'ee/app/assets/javascripts/oncall_schedules/components/add_edit_schedule_form.vue', + 'ee/app/assets/javascripts/oncall_schedules/components/oncall_schedule.vue', + 'ee/app/assets/javascripts/oncall_schedules/components/rotations/components/rotation_assignee.vue', + 'ee/app/assets/javascripts/oncall_schedules/components/schedule/components/preset_days/days_header_sub_item.vue', + 'ee/app/assets/javascripts/oncall_schedules/components/schedule/components/preset_weeks/weeks_header_item.vue', + 'ee/app/assets/javascripts/operations/components/dashboard/dashboard.vue', + 'ee/app/assets/javascripts/operations/components/dashboard/project.vue', + 'ee/app/assets/javascripts/operations/components/dashboard/project_header.vue', + 'ee/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/container_scanning_counts.vue', + 'ee/app/assets/javascripts/packages_and_registries/settings/project/components/dependency_proxy_packages_settings_form.vue', + 'ee/app/assets/javascripts/product_analytics/onboarding/components/providers/self_managed_provider_card.vue', + 'ee/app/assets/javascripts/product_analytics/onboarding/settings_instrumentation_instructions.vue', + 'ee/app/assets/javascripts/projects/components/move_personal_project_to_group_modal.vue', + 'ee/app/assets/javascripts/projects/merge_requests/blocking_mr_input_root.vue', + 'ee/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue', + 'ee/app/assets/javascripts/protected_environments/create_protected_environment.vue', + 'ee/app/assets/javascripts/protected_environments/edit_protected_environment_rules_card.vue', + 'ee/app/assets/javascripts/protected_environments/protected_environments.vue', + 'ee/app/assets/javascripts/related_items_tree/components/create_epic_form.vue', + 'ee/app/assets/javascripts/related_items_tree/components/related_items_tree_app.vue', + 'ee/app/assets/javascripts/related_items_tree/components/related_items_tree_header_actions.vue', + 'ee/app/assets/javascripts/related_items_tree/components/tree_root.vue', + 'ee/app/assets/javascripts/requirements/components/export_requirements_modal.vue', + 'ee/app/assets/javascripts/requirements/components/import_requirements_modal.vue', + 'ee/app/assets/javascripts/requirements/components/requirements_root.vue', + 'ee/app/assets/javascripts/roadmap/components/current_day_indicator.vue', + 'ee/app/assets/javascripts/roadmap/components/epic_item.vue', + 'ee/app/assets/javascripts/roadmap/components/epic_item_details.vue', + 'ee/app/assets/javascripts/roadmap/components/epic_item_timeline.vue', + 'ee/app/assets/javascripts/roadmap/components/epics_list_empty.vue', + 'ee/app/assets/javascripts/roadmap/components/milestone_item.vue', + 'ee/app/assets/javascripts/roadmap/components/milestones_list_section.vue', + 'ee/app/assets/javascripts/roadmap/components/preset_months/months_header_sub_item.vue', + 'ee/app/assets/javascripts/roadmap/components/preset_quarters/quarters_header_item.vue', + 'ee/app/assets/javascripts/roadmap/components/preset_quarters/quarters_header_sub_item.vue', + 'ee/app/assets/javascripts/roadmap/components/preset_weeks/weeks_header_item.vue', + 'ee/app/assets/javascripts/roadmap/components/preset_weeks/weeks_header_sub_item.vue', + 'ee/app/assets/javascripts/roadmap/components/roadmap_app.vue', + 'ee/app/assets/javascripts/roadmap/components/roadmap_daterange.vue', + 'ee/app/assets/javascripts/roadmap/components/roadmap_filters.vue', + 'ee/app/assets/javascripts/roadmap/components/roadmap_shell.vue', + 'ee/app/assets/javascripts/roadmap/components/roadmap_timeline_section.vue', + 'ee/app/assets/javascripts/security_configuration/components/configuration_page_layout.vue', + 'ee/app/assets/javascripts/security_configuration/components/configuration_snippet_modal.vue', + 'ee/app/assets/javascripts/security_configuration/components/container_scanning_for_registry_feature_card.vue', + 'ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_upload_button.vue', + 'ee/app/assets/javascripts/security_configuration/dast_pre_scan_verification/components/pre_scan_verification_alert.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/components/base_dast_profile_form.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/components/dast_profiles_list.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/components/dast_site_profiles_list.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/components/dast_variables_form_group.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/components/dast_variables_modal.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profile_selector/site_profile_summary.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/dast_profiles_configurator/dast_profiles_configurator.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/dast_scanner_profiles/components/dast_scanner_profile_form.vue', + 'ee/app/assets/javascripts/security_configuration/dast_profiles/dast_site_profiles/components/dast_site_profile_form.vue', + 'ee/app/assets/javascripts/security_configuration/dast_site_validation/components/dast_site_validation_modal.vue', + 'ee/app/assets/javascripts/security_configuration/dast_site_validation/components/dast_site_validation_revoke_modal.vue', + 'ee/app/assets/javascripts/security_configuration/sast/components/app.vue', + 'ee/app/assets/javascripts/security_configuration/secret_detection/components/exclusion_delete_modal.vue', + 'ee/app/assets/javascripts/security_configuration/secret_detection/components/exclusion_form_drawer.vue', + 'ee/app/assets/javascripts/security_dashboard/components/agent/agent_vulnerability_report.vue', + 'ee/app/assets/javascripts/security_dashboard/components/pipeline/pipeline_vulnerability_report.vue', + 'ee/app/assets/javascripts/security_dashboard/components/pipeline/vulnerability_finding_modal.vue', + 'ee/app/assets/javascripts/security_dashboard/components/project/project_security_dashboard.vue', + 'ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_list_graphql.vue', + 'ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_report_tab.vue', + 'ee/app/assets/javascripts/security_dashboard/components/shared/vulnerability_report/vulnerability_report_tabs.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/branch_selector_modal.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_layout.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/editor_wrapper.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/pipeline_execution/editor_component.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/editor_component.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/editor_component.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/rule/default_rule_builder.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/rule/deny_allow_list_modal.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_result/settings/block_group_branch_modification.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/scope_group_selector.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/scope/scope_section.vue', + 'ee/app/assets/javascripts/security_orchestration/components/policy_editor/vulnerability_management/editor_component.vue', + 'ee/app/assets/javascripts/security_orchestration/components/shared/linked_items_dropdown.vue', + 'ee/app/assets/javascripts/security_orchestration/components/shared/multiple_groups_projects_dropdown.vue', + 'ee/app/assets/javascripts/sidebar/components/health_status/health_status_dropdown.vue', + 'ee/app/assets/javascripts/sidebar/components/incidents/escalation_status.vue', + 'ee/app/assets/javascripts/sidebar/components/weight/sidebar_weight_widget.vue', + 'ee/app/assets/javascripts/status_checks/components/modal_delete.vue', + 'ee/app/assets/javascripts/status_checks/components/modal_update.vue', + 'ee/app/assets/javascripts/status_checks/components/shared_modal.vue', + 'ee/app/assets/javascripts/test_case_show/components/test_case_sidebar.vue', + 'ee/app/assets/javascripts/tracing/details/related_issues/related_issues_provider.vue', + 'ee/app/assets/javascripts/tracing/details/tracing_details.vue', + 'ee/app/assets/javascripts/usage_quotas/code_suggestions/components/code_suggestions_info_card.vue', + 'ee/app/assets/javascripts/usage_quotas/code_suggestions/components/search_and_sort_bar.vue', + 'ee/app/assets/javascripts/usage_quotas/pipelines/components/app.vue', + 'ee/app/assets/javascripts/usage_quotas/pipelines/components/minutes_usage_per_project_chart.vue', + 'ee/app/assets/javascripts/usage_quotas/pipelines/components/shared_runner_usage_month_chart.vue', + 'ee/app/assets/javascripts/usage_quotas/seats/components/statistics_seats_card.vue', + 'ee/app/assets/javascripts/usage_quotas/transfer/components/usage_by_month.vue', + 'ee/app/assets/javascripts/users/identity_verification/components/credit_card_verification.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/components/blocking_merge_requests/blocking_merge_request_body.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/components/blocking_merge_requests/blocking_merge_requests_report.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/components/checks/not_approved.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/components/checks/requested_changes.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/components/merge_immediately_confirmation_dialog.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_policy_violation.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/components/widget/app.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue', + 'ee/app/assets/javascripts/vue_merge_request_widget/widgets/status_checks/index.vue', + 'ee/app/assets/javascripts/vue_shared/components/code_flow/code_flow_steps_section.vue', + 'ee/app/assets/javascripts/vue_shared/components/code_flow/vulnerability_code_flow.vue', + 'ee/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/epic_token.vue', + 'ee/app/assets/javascripts/vue_shared/discover/card_security_discover_app.vue', + 'ee/app/assets/javascripts/vue_shared/security_reports/components/security_training_promo.vue', + 'ee/app/assets/javascripts/vulnerabilities/components/header.vue', + 'ee/app/assets/javascripts/vulnerabilities/components/new_vulnerability/section_details.vue', + 'ee/app/assets/javascripts/vulnerabilities/components/vulnerability_details.vue', + 'ee/app/assets/javascripts/vulnerabilities/components/vulnerability_training.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_change_type_modal.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_color.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_custom_fields_multi_select.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_custom_fields_number.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_custom_fields_single_select.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_custom_fields_text.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_development/work_item_development_ff_item.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_health_status.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_iteration.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_links/work_item_rolled_up_health_status.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_progress.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_rolledup_dates.vue', + 'ee/app/assets/javascripts/work_items/components/work_item_weight.vue', + 'ee/app/assets/javascripts/workspaces/common/components/workspaces_list/workspaces_table.vue', + 'ee/app/assets/javascripts/workspaces/dropdown_group/components/workspace_dropdown_item.vue', + 'ee/app/assets/javascripts/workspaces/user/pages/list.vue', + ], + rules: { + 'vue/no-unused-properties': 'off', + }, +}; diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index d523c2cce15a1bb3146916eb4857f75e989a8fd9..726a872dc4d7dd059981b3f8dad96eb6e48ad5f4 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -515,6 +515,7 @@ .code-backstage-patterns: &code-backstage-patterns - ".{gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - "eslint.config.mjs" + - ".eslint_todo/*.mjs" - ".browserslistrc" - ".stylelintrc" - "{,ee/,jh/}{app,bin,config,db,elastic,generator_templates,gems,haml_lint,lib,locale,public,scripts,sidekiq_cluster,storybook,symbol,vendor}/**/*" diff --git a/doc/development/fe_guide/tooling.md b/doc/development/fe_guide/tooling.md index 06e06a254fcfafbfc7cf3bdda2fafbb193a08852..af2188154401617db0a9b50e77b4c2863f8ad355 100644 --- a/doc/development/fe_guide/tooling.md +++ b/doc/development/fe_guide/tooling.md @@ -90,6 +90,47 @@ import Foo from 'foo'; new Foo(); ``` +### Generating todo files + +When enabling a new ESLint rule that uncovers many offenses across the codebase, it might be easier +to generate a todo file to temporarily ignore those offenses. This approach has some pros and cons: + +**Pros:** + +- A single source of truth for all the files that violate a specific rule. This can make it easier + to track the work necessary to pay the incurred technical debt. +- A smaller changeset when initially enabling the rule as you don't need to modify every offending + file. + +**Cons:** + +- Disabling the rule for entire files means that more offenses of the same type can be introduced in + those files. +- When fixing offenses over multiple concurrent merge requests, conflicts can often arise in the todo files, + requiring MR authors to rebase their branches. + +To generate a todo file, run the `scripts/frontend/generate_eslint_todo_list.mjs` script: + +```shell +node scripts/frontend/generate_eslint_todo_list.mjs <rule_name> +``` + +For example, generating a todo file for the `vue/no-unused-properties` rule: + +```shell +node scripts/frontend/generate_eslint_todo_list.mjs vue/no-unused-properties +``` + +This creates an ESLint configuration in `.eslint_todo/vue-no-unused-properties.mjs` which gets +automatically added to the global configuration. + +Once a todo file has been created for a given rule, make sure to plan for the work necessary to +address those violations. Todo files should be as short lived as possible. If some offenses cannot +be addressed, switch to inline ignores by [disabling ESLint for a single violation](#disabling-eslint-for-a-single-violation). + +When all offending files have been fixed, the todo file should be removed along with the `export` +statement in `.eslint_todo/index.mjs`. + ### The `no-undef` rule and declaring globals **Never** disable the `no-undef` rule. Declare globals with `/* global Foo */` instead. diff --git a/eslint.config.mjs b/eslint.config.mjs index feb73d8cee500970d2633dfb98ce68d9d44768a4..fb0697de8448f6e6561cc941da5cd3360327e27c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -5,6 +5,7 @@ import localRules from 'eslint-plugin-local-rules'; import js from '@eslint/js'; import { FlatCompat } from '@eslint/eslintrc'; import * as graphqlEslint from '@graphql-eslint/eslint-plugin'; +import * as todoLists from './.eslint_todo/index.mjs' const { dirname } = import.meta; const compat = new FlatCompat({ @@ -395,6 +396,17 @@ export default [ 'local-rules/vue-require-valid-help-page-link-component': 'error', }, }, + { + files: ['**/*.vue'], + rules: { + 'vue/no-unused-properties': [ + 'error', + { + groups: ['props', 'data', 'computed', 'methods'], + }, + ], + }, + }, { files: ['{,ee/,jh/}spec/frontend*/**/*'], @@ -719,4 +731,5 @@ export default [ }, }, ...jhConfigs, + ...Object.values(todoLists), ]; diff --git a/scripts/frontend/generate_eslint_todo_list.mjs b/scripts/frontend/generate_eslint_todo_list.mjs new file mode 100644 index 0000000000000000000000000000000000000000..9d633d1d066080e4f40d42023bc7c4381a17ed84 --- /dev/null +++ b/scripts/frontend/generate_eslint_todo_list.mjs @@ -0,0 +1,164 @@ +import path from 'node:path'; +import fs from 'node:fs'; +import { ESLint } from 'eslint'; +import { program } from 'commander'; +import * as prettier from 'prettier'; +import kebabCase from 'lodash/kebabCase.js'; +import camelCase from 'lodash/camelCase.js'; +import sortBy from 'lodash/sortBy.js'; +import eslintConfig from '../../eslint.config.mjs'; + +const ROOT_PATH = path.resolve(import.meta.dirname, '../../'); + +function createESLintInstance(overrideConfig) { + return new ESLint({ overrideConfigFile: true, overrideConfig, fix: false }); +} + +function lint(eslint, filePaths) { + return eslint.lintFiles(filePaths); +} + +/** + * Creates a barebone ESLint config to lint the codebase with. We only keep configs that make use + * of the rule we are generating a todo file for. If no config use the rule, this returns `null` and + * should cause the script to abort its execution. + * + * @param {string} rule The rule to generate a todo file for. + * @returns {object|null} The config to use for the rule. + */ +function getConfigForRule(rule) { + let configHasRule = false; + const newConfig = eslintConfig + .map((config) => { + // We preserve existing configs for the rule so that we don't add valid files to the todo file. + // However, we bypass configs that disabled the rule as those are likely the todo files themselves. + const hasRuleDefinition = config.rules?.[rule] && config.rules[rule] !== 'off'; + if (hasRuleDefinition) { + configHasRule = true; + return { + ...config, + rules: { + [rule]: config.rules[rule], + }, + }; + } + + return { + ...config, + rules: {}, + }; + }) + .filter((config) => config !== null); + + if (configHasRule) { + return newConfig; + } + return null; +} + +function getOffendingFiles(results, rule) { + return results.reduce((acc, result) => { + const hasRuleError = result.messages.some((message) => message.ruleId === rule); + if (hasRuleError) { + acc.push(result.filePath); + } + return acc; + }, []); +} + +async function prettify(data) { + const prettierConfig = await prettier.resolveConfig(path.join(ROOT_PATH, '.prettierrc')); + return prettier.format(data, { + ...prettierConfig, + parser: 'babel', + }); +} + +async function writeTodoFile(rule, offendingFiles) { + const slugifiedRule = kebabCase(rule); + const todoFileName = `${slugifiedRule}.mjs`; + const todoFilePath = path.join(ROOT_PATH, '.eslint_todo', todoFileName); + const camelCasedRule = camelCase(rule); + const relativePaths = sortBy(offendingFiles.map((file) => path.relative(ROOT_PATH, file))) + .map((relativePath) => `'${relativePath}'`) + .join(',\n'); + const indexFilePath = path.join(ROOT_PATH, '.eslint_todo', 'index.mjs'); + const indexFileContent = fs.readFileSync(indexFilePath, { encoding: 'utf-8' }); + + console.log(`Writing todo file to ${todoFilePath}.`); + + const newConfig = ` + /** + * Generated by \`scripts/frontend/generate_eslint_todo_list.mjs\`. + */ + export default { + files: [${relativePaths}], + rules: { + '${rule}': 'off', + }, + } + `; + + const formattedTodoFileContent = await prettify(newConfig); + + fs.writeFileSync(todoFilePath, formattedTodoFileContent); + + if (!indexFileContent.match(camelCasedRule)) { + console.log(`Adding export statement to ${indexFilePath}.`); + const exportStatement = `export { default as ${camelCasedRule} } from './${todoFileName}';`; + const newIndexFileContent = `${indexFileContent}\n${exportStatement}`; + const formattedNewIndexFileContent = await prettify(newIndexFileContent); + fs.writeFileSync(indexFilePath, formattedNewIndexFileContent); + } else { + console.log(`Export statement already exists in ${indexFilePath}.`); + } +} + +async function main() { + program + .description( + 'Generates a todo file to skip linting on offending files for a specific ESLint rule.', + ) + .option('--debug-config', 'Prints the ESLint config used to generate the todo file.') + .argument('<rule>') + .parse(process.argv); + const options = program.opts(); + const [rule] = program.args; + + console.log(`Generating todo file for rule \`${rule}\`...`); + + const overrideConfig = getConfigForRule(rule); + + if (overrideConfig === null) { + console.error( + `The rule \`${rule}\` could not be found in the ESLint configuration. It needs to be enabled before generating a todo file.`, + ); + process.exitCode = 1; + return; + } + + if (options.debugConfig) { + console.log('Using ESLint configuration:'); + console.log(overrideConfig); + } + + const eslint = createESLintInstance(overrideConfig); + const results = await lint(eslint, [ + './app/assets/javascripts/**/*.{js,mjs,cjs,vue}', + './ee/app/assets/javascripts/**/*.{js,mjs,cjs,vue}', + './spec/frontend/**/*.js', + './ee/spec/frontend/**/*.js', + 'scripts/**/*.{js,mjs,cjs}', + ]); + + const offendingFiles = getOffendingFiles(results, rule); + if (offendingFiles.length > 0) { + console.log(`Found ${offendingFiles.length} offending files.`); + await writeTodoFile(rule, offendingFiles); + } else { + console.error('No offenses found. Delete any existing todo file if it is not needed anymore.'); + process.exitCode = 1; + } +} + +main();