Commit f049b19c authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch 'cngo-improve-csv-import-buttons-code' into 'master'

Improve CSV import/export buttons code

See merge request gitlab-org/gitlab!71581
parents 15238108 dc523ddd
<script> <script>
import { GlButton, GlModal, GlSprintf, GlIcon } from '@gitlab/ui'; import { GlButton, GlModal, GlSprintf, GlIcon } from '@gitlab/ui';
import { __, n__ } from '~/locale';
import { ISSUABLE_TYPE } from '../constants'; import { ISSUABLE_TYPE } from '../constants';
export default { export default {
name: 'CsvExportModal', i18n: {
exportText: __(
'The CSV export will be created in the background. Once finished, it will be sent to %{email} in an attachment.',
),
},
components: { components: {
GlButton, GlButton,
GlModal, GlModal,
...@@ -32,53 +37,39 @@ export default { ...@@ -32,53 +37,39 @@ export default {
required: true, required: true,
}, },
}, },
data() { computed: {
return { isIssue() {
// eslint-disable-next-line @gitlab/require-i18n-strings return this.issuableType === ISSUABLE_TYPE.issues;
issuableName: this.issuableType === ISSUABLE_TYPE.issues ? 'issues' : 'merge requests', },
}; exportText() {
return this.isIssue ? __('Export issues') : __('Export merge requests');
},
issuableCountText() {
return this.isIssue
? n__('1 issue selected', '%d issues selected', this.issuableCount)
: n__('1 merge request selected', '%d merge requests selected', this.issuableCount);
},
}, },
issueableType: ISSUABLE_TYPE,
}; };
</script> </script>
<template> <template>
<gl-modal :modal-id="modalId" body-class="gl-p-0!" data-qa-selector="export_issuable_modal"> <gl-modal
<template #modal-title> :modal-id="modalId"
<gl-sprintf :message="__('Export %{name}')"> body-class="gl-p-0!"
<template #name>{{ issuableName }}</template> :title="exportText"
</gl-sprintf> data-qa-selector="export_issuable_modal"
</template> >
<div <div
v-if="issuableCount > -1"
class="gl-justify-content-start gl-align-items-center gl-p-4 gl-border-b-solid gl-border-1 gl-border-gray-50" class="gl-justify-content-start gl-align-items-center gl-p-4 gl-border-b-solid gl-border-1 gl-border-gray-50"
> >
<gl-icon name="check" class="gl-color-green-400" /> <gl-icon name="check" class="gl-color-green-400" />
<strong class="gl-m-3"> <strong class="gl-m-3">{{ issuableCountText }}</strong>
<gl-sprintf
v-if="issuableType === $options.issueableType.issues"
:message="n__('1 issue selected', '%d issues selected', issuableCount)"
>
<template #issuableCount>{{ issuableCount }}</template>
</gl-sprintf>
<gl-sprintf
v-else
:message="n__('1 merge request selected', '%d merge requests selected', issuableCount)"
>
<template #issuableCount>{{ issuableCount }}</template>
</gl-sprintf>
</strong>
</div> </div>
<div class="modal-text gl-px-4 gl-py-5"> <div class="modal-text gl-px-4 gl-py-5">
<gl-sprintf <gl-sprintf :message="$options.i18n.exportText">
:message=" <template #email>
__( <strong>{{ email }}</strong>
`The CSV export will be created in the background. Once finished, it will be sent to %{strongStart}${email}%{strongEnd} in an attachment.`,
)
"
>
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template> </template>
</gl-sprintf> </gl-sprintf>
</div> </div>
...@@ -92,9 +83,7 @@ export default { ...@@ -92,9 +83,7 @@ export default {
data-track-action="click_button" data-track-action="click_button"
:data-track-label="`export_${issuableType}_csv`" :data-track-label="`export_${issuableType}_csv`"
> >
<gl-sprintf :message="__('Export %{name}')"> {{ exportText }}
<template #name>{{ issuableName }}</template>
</gl-sprintf>
</gl-button> </gl-button>
</template> </template>
</gl-modal> </gl-modal>
......
...@@ -15,6 +15,8 @@ import CsvImportModal from './csv_import_modal.vue'; ...@@ -15,6 +15,8 @@ import CsvImportModal from './csv_import_modal.vue';
export default { export default {
i18n: { i18n: {
exportAsCsvButtonText: __('Export as CSV'), exportAsCsvButtonText: __('Export as CSV'),
importCsvText: __('Import CSV'),
importFromJiraText: __('Import from Jira'),
importIssuesText: __('Import issues'), importIssuesText: __('Import issues'),
}, },
name: 'CsvImportExportButtons', name: 'CsvImportExportButtons',
...@@ -101,13 +103,16 @@ export default { ...@@ -101,13 +103,16 @@ export default {
:text-sr-only="!showLabel" :text-sr-only="!showLabel"
:icon="importButtonIcon" :icon="importButtonIcon"
> >
<gl-dropdown-item v-gl-modal="importModalId">{{ __('Import CSV') }}</gl-dropdown-item> <gl-dropdown-item v-gl-modal="importModalId">
{{ $options.i18n.importCsvText }}
</gl-dropdown-item>
<gl-dropdown-item <gl-dropdown-item
v-if="canEdit" v-if="canEdit"
:href="projectImportJiraPath" :href="projectImportJiraPath"
data-qa-selector="import_from_jira_link" data-qa-selector="import_from_jira_link"
>{{ __('Import from Jira') }}</gl-dropdown-item
> >
{{ $options.i18n.importFromJiraText }}
</gl-dropdown-item>
</gl-dropdown> </gl-dropdown>
</gl-button-group> </gl-button-group>
<csv-export-modal <csv-export-modal
......
<script> <script>
import { GlModal, GlSprintf, GlFormGroup, GlButton } from '@gitlab/ui'; import { GlModal, GlFormGroup } from '@gitlab/ui';
import csrf from '~/lib/utils/csrf'; import csrf from '~/lib/utils/csrf';
import { ISSUABLE_TYPE } from '../constants'; import { __, sprintf } from '~/locale';
export default { export default {
name: 'CsvImportModal', i18n: {
maximumFileSizeText: __('The maximum file size allowed is %{size}.'),
importIssuesText: __('Import issues'),
uploadCsvFileText: __('Upload CSV file'),
mainText: __(
"Your issues will be imported in the background. Once finished, you'll get a confirmation email.",
),
helpText: __(
'It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected.',
),
},
actionPrimary: {
text: __('Import issues'),
},
components: { components: {
GlModal, GlModal,
GlSprintf,
GlFormGroup, GlFormGroup,
GlButton,
}, },
inject: { inject: {
issuableType: {
default: '',
},
exportCsvPath: {
default: '',
},
importCsvIssuesPath: { importCsvIssuesPath: {
default: '', default: '',
}, },
...@@ -31,11 +36,10 @@ export default { ...@@ -31,11 +36,10 @@ export default {
required: true, required: true,
}, },
}, },
data() { computed: {
return { maxFileSizeText() {
// eslint-disable-next-line @gitlab/require-i18n-strings return sprintf(this.$options.i18n.maximumFileSizeText, { size: this.maxAttachmentSize });
issuableName: this.issuableType === ISSUABLE_TYPE.issues ? 'issues' : 'merge requests', },
};
}, },
methods: { methods: {
submitForm() { submitForm() {
...@@ -47,34 +51,22 @@ export default { ...@@ -47,34 +51,22 @@ export default {
</script> </script>
<template> <template>
<gl-modal :modal-id="modalId" :title="__('Import issues')"> <gl-modal
:modal-id="modalId"
:title="$options.i18n.importIssuesText"
:action-primary="$options.actionPrimary"
@primary="submitForm"
>
<form ref="form" :action="importCsvIssuesPath" enctype="multipart/form-data" method="post"> <form ref="form" :action="importCsvIssuesPath" enctype="multipart/form-data" method="post">
<input :value="$options.csrf.token" type="hidden" name="authenticity_token" /> <input :value="$options.csrf.token" type="hidden" name="authenticity_token" />
<p> <p>{{ $options.i18n.mainText }}</p>
{{ <gl-form-group :label="$options.i18n.uploadCsvFileText" label-for="file">
__(
"Your issues will be imported in the background. Once finished, you'll get a confirmation email.",
)
}}
</p>
<gl-form-group :label="__('Upload CSV file')" label-for="file">
<input id="file" type="file" name="file" accept=".csv,text/csv" /> <input id="file" type="file" name="file" accept=".csv,text/csv" />
</gl-form-group> </gl-form-group>
<p class="text-secondary"> <p class="text-secondary">
{{ {{ $options.i18n.helpText }}
__( {{ maxFileSizeText }}
'It must have a header row and at least two columns: the first column is the issue title and the second column is the issue description. The separator is automatically detected.',
)
}}
<gl-sprintf :message="__('The maximum file size allowed is %{size}.')"
><template #size>{{ maxAttachmentSize }}</template></gl-sprintf
>
</p> </p>
</form> </form>
<template #modal-footer>
<gl-button category="primary" variant="confirm" @click="submitForm">{{
__('Import issues')
}}</gl-button>
</template>
</gl-modal> </gl-modal>
</template> </template>
...@@ -13851,9 +13851,6 @@ msgstr "" ...@@ -13851,9 +13851,6 @@ msgstr ""
msgid "Export" msgid "Export"
msgstr "" msgstr ""
msgid "Export %{name}"
msgstr ""
msgid "Export %{requirementsCount} requirements?" msgid "Export %{requirementsCount} requirements?"
msgstr "" msgstr ""
...@@ -13866,6 +13863,12 @@ msgstr "" ...@@ -13866,6 +13863,12 @@ msgstr ""
msgid "Export group" msgid "Export group"
msgstr "" msgstr ""
msgid "Export issues"
msgstr ""
msgid "Export merge requests"
msgstr ""
msgid "Export project" msgid "Export project"
msgstr "" msgstr ""
...@@ -33627,6 +33630,9 @@ msgstr[1] "" ...@@ -33627,6 +33630,9 @@ msgstr[1] ""
msgid "The API key used by GitLab for accessing the Spam Check service endpoint." msgid "The API key used by GitLab for accessing the Spam Check service endpoint."
msgstr "" msgstr ""
msgid "The CSV export will be created in the background. Once finished, it will be sent to %{email} in an attachment."
msgstr ""
msgid "The GitLab subscription service (customers.gitlab.com) is currently experiencing an outage. You can monitor the status and get updates at %{linkStart}status.gitlab.com%{linkEnd}." msgid "The GitLab subscription service (customers.gitlab.com) is currently experiencing an outage. You can monitor the status and get updates at %{linkStart}status.gitlab.com%{linkEnd}."
msgstr "" msgstr ""
......
...@@ -61,11 +61,6 @@ describe('CsvExportModal', () => { ...@@ -61,11 +61,6 @@ describe('CsvExportModal', () => {
expect(wrapper.text()).toContain('10 issues selected'); expect(wrapper.text()).toContain('10 issues selected');
expect(findIcon().exists()).toBe(true); expect(findIcon().exists()).toBe(true);
}); });
it("doesn't display the info text when issuableCount is -1", () => {
wrapper = createComponent({ props: { issuableCount: -1 } });
expect(wrapper.text()).not.toContain('issues selected');
});
}); });
describe('email info text', () => { describe('email info text', () => {
......
...@@ -17,7 +17,6 @@ describe('CsvImportModal', () => { ...@@ -17,7 +17,6 @@ describe('CsvImportModal', () => {
...props, ...props,
}, },
provide: { provide: {
issuableType: 'issues',
...injectedProperties, ...injectedProperties,
}, },
stubs: { stubs: {
...@@ -43,9 +42,9 @@ describe('CsvImportModal', () => { ...@@ -43,9 +42,9 @@ describe('CsvImportModal', () => {
const findAuthenticityToken = () => new FormData(findForm().element).get('authenticity_token'); const findAuthenticityToken = () => new FormData(findForm().element).get('authenticity_token');
describe('template', () => { describe('template', () => {
it('displays modal title', () => { it('passes correct title props to modal', () => {
wrapper = createComponent(); wrapper = createComponent();
expect(findModal().text()).toContain('Import issues'); expect(findModal().props('title')).toContain('Import issues');
}); });
it('displays a note about the maximum allowed file size', () => { it('displays a note about the maximum allowed file size', () => {
...@@ -73,7 +72,7 @@ describe('CsvImportModal', () => { ...@@ -73,7 +72,7 @@ describe('CsvImportModal', () => {
}); });
it('submits the form when the primary action is clicked', () => { it('submits the form when the primary action is clicked', () => {
findPrimaryButton().trigger('click'); findModal().vm.$emit('primary');
expect(formSubmitSpy).toHaveBeenCalled(); expect(formSubmitSpy).toHaveBeenCalled();
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment