diff --git a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/code_block_file_path.vue b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/code_block_file_path.vue index 6641b39e556b19b484b6a7d0a2cb15287ed5abc7..afedeba2f3cb7c696c229d780c9431e8b33911e2 100644 --- a/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/code_block_file_path.vue +++ b/ee/app/assets/javascripts/security_orchestration/components/policy_editor/scan_execution/action/code_block_file_path.vue @@ -5,9 +5,11 @@ import { GlInputGroupText, GlSprintf, GlFormInput, + GlTooltipDirective, GlTruncate, } from '@gitlab/ui'; import { s__, __ } from '~/locale'; +import { BV_SHOW_TOOLTIP, BV_HIDE_TOOLTIP } from '~/lib/utils/constants'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import RefSelector from '~/ref/components/ref_selector.vue'; import CodeBlockSourceSelector from 'ee/security_orchestration/components/policy_editor/scan_execution/action/code_block_source_selector.vue'; @@ -20,7 +22,7 @@ export default { filePathCopy: s__( 'ScanExecutionPolicy|%{boldStart}Run%{boldEnd} %{typeSelector} from the project %{projectSelector} with ref %{refSelector}', ), - filePathPrependLabel: __('Select project'), + filePathPrependLabel: __('No project selected'), fileRefLabel: s__('ScanExecutionPolicy|Select ref'), filePathInputPlaceholder: s__('ScanExecutionPolicy|Link existing CI file'), filePathInputEmptyMessage: s__("ScanExecutionPolicy|The file path can't be empty"), @@ -28,10 +30,12 @@ export default { "ScanExecutionPolicy|The file at that project, ref, and path doesn't exist", ), formGroupLabel: s__('ScanExecutionPolicy|file path group'), + tooltipText: s__('ScanExecutionPolicy|Select project first, and then insert a file path'), }, refSelectorTranslations: { noRefSelected: __('default branch'), }, + SELECTED_PROJECT_TOOLTIP: 'selected-project-tooltip', name: 'CodeBlockFilePath', components: { CodeBlockSourceSelector, @@ -44,6 +48,7 @@ export default { GroupProjectsDropdown, RefSelector, }, + directives: { GlTooltip: GlTooltipDirective }, inject: ['namespacePath', 'rootNamespacePath', 'namespaceType'], props: { selectedType: { @@ -107,6 +112,9 @@ export default { selectedProjectFullPath() { return this.selectedProject?.fullPath || this.$options.i18n.filePathPrependLabel; }, + selectedProjectTooltip() { + return this.selectedProject?.fullPath || this.$options.i18n.tooltipText; + }, groupProjectsPath() { return this.namespaceType === NAMESPACE_TYPES.GROUP ? this.namespacePath @@ -126,6 +134,10 @@ export default { setSelectedRef(ref) { this.$emit('select-ref', ref); }, + triggerTooltip(state) { + const EVENT = state ? BV_SHOW_TOOLTIP : BV_HIDE_TOOLTIP; + this.$root.$emit(EVENT, this.$options.SELECTED_PROJECT_TOOLTIP); + }, }, }; </script> @@ -196,12 +208,22 @@ export default { id="file-path" :placeholder="$options.i18n.filePathInputPlaceholder" :state="filePathState" + :disabled="!selectedProjectId" :value="filePath" + @mouseenter="triggerTooltip(true)" + @mouseleave="triggerTooltip(false)" @input="updatedFilePath" > <template #prepend> - <gl-input-group-text class="gl-max-w-26 gl-max-h-full!"> - <gl-truncate :text="selectedProjectFullPath" position="start" with-tooltip /> + <gl-input-group-text + v-gl-tooltip="{ + id: $options.SELECTED_PROJECT_TOOLTIP, + title: selectedProjectTooltip, + }" + :class="{ 'gl-border-gray-100': !selectedProjectId }" + class="gl-max-w-26 gl-max-h-full!" + > + <gl-truncate :text="selectedProjectFullPath" position="start" /> </gl-input-group-text> </template> </gl-form-input-group> diff --git a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/code_block_file_path_spec.js b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/code_block_file_path_spec.js index b67e9896822379c9b217d46d186833d31bc6abf5..b227654b88153cb71d6322c68511b5a52a58f7a2 100644 --- a/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/code_block_file_path_spec.js +++ b/ee/spec/frontend/security_orchestration/components/policy_editor/scan_execution/action/code_block_file_path_spec.js @@ -46,6 +46,8 @@ describe('CodeBlockFilePath', () => { it('renders file path', () => { expect(findFormGroup().exists()).toBe(true); expect(findFormInputGroup().exists()).toBe(true); + expect(findFormInputGroup().attributes().disabled).toBe('true'); + expect(findTruncate().props('text')).toBe('No project selected'); }); it('renders ref input', () => { @@ -77,17 +79,19 @@ describe('CodeBlockFilePath', () => { }); it('renders selected project and ref selector', () => { + const fullPath = 'path/to/project'; + createComponent({ propsData: { selectedProject: { id: PROJECT_ID, - fullPath: 'fullPath', + fullPath, }, selectedRef: 'ref', }, }); - expect(findTruncate().props('text')).toBe('fullPath'); + expect(findTruncate().props('text')).toBe(fullPath); expect(findRefSelector().exists()).toBe(true); expect(findFormInput().exists()).toBe(false); expect(findRefSelector().props()).toEqual( @@ -99,6 +103,8 @@ describe('CodeBlockFilePath', () => { }), ); expect(findGroupProjectsDropdown().props('selected')).toBe(PROJECT_ID); + expect(findFormInputGroup().attributes().disabled).toBe(undefined); + expect(findTruncate().props('text')).toBe(fullPath); }); it('renders selected file path', () => { diff --git a/locale/gitlab.pot b/locale/gitlab.pot index fcab4053ad55efb67deba990aa7e631a064e112a..f2b0e430e7b08b4338c28004f4c671376cdb0734 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -33463,6 +33463,9 @@ msgstr "" msgid "No prioritized labels yet!" msgstr "" +msgid "No project selected" +msgstr "" + msgid "No project subscribes to the pipelines in this project." msgstr "" @@ -44337,6 +44340,9 @@ msgstr "" msgid "ScanExecutionPolicy|Select or Create a Key" msgstr "" +msgid "ScanExecutionPolicy|Select project first, and then insert a file path" +msgstr "" + msgid "ScanExecutionPolicy|Select ref" msgstr ""