Commit 26fb57df authored by Illya Klymov's avatar Illya Klymov Committed by Jacques Erasmus

Address reviewer comments

- fix empty spaces
- simplify helpers
- add more tests
parent 36ed0aa9
...@@ -27,7 +27,6 @@ export default { ...@@ -27,7 +27,6 @@ export default {
? `${this.group.last_import_target.target_namespace}/${this.group.last_import_target.new_name}` ? `${this.group.last_import_target.target_namespace}/${this.group.last_import_target.new_name}`
: null; : null;
}, },
absoluteLastImportPath() { absoluteLastImportPath() {
return joinPaths(gon.relative_url_root || '/', this.fullLastImportPath); return joinPaths(gon.relative_url_root || '/', this.fullLastImportPath);
}, },
...@@ -46,16 +45,6 @@ export default { ...@@ -46,16 +45,6 @@ export default {
<template> <template>
<span class="gl-white-space-nowrap gl-inline-flex gl-align-items-center"> <span class="gl-white-space-nowrap gl-inline-flex gl-align-items-center">
<gl-icon
v-if="isFinished"
v-gl-tooltip
:size="16"
name="information-o"
:title="
s__('BulkImports|Re-import creates a new group. It does not sync with the existing group.')
"
class="gl-mr-3"
/>
<gl-button <gl-button
v-if="isAvailableForImport" v-if="isAvailableForImport"
:disabled="isInvalid" :disabled="isInvalid"
...@@ -66,5 +55,15 @@ export default { ...@@ -66,5 +55,15 @@ export default {
> >
{{ isFinished ? __('Re-import') : __('Import') }} {{ isFinished ? __('Re-import') : __('Import') }}
</gl-button> </gl-button>
<gl-icon
v-if="isFinished"
v-gl-tooltip
:size="16"
name="information-o"
:title="
s__('BulkImports|Re-import creates a new group. It does not sync with the existing group.')
"
class="gl-ml-3"
/>
</span> </span>
</template> </template>
...@@ -21,7 +21,6 @@ export default { ...@@ -21,7 +21,6 @@ export default {
? `${this.group.last_import_target.target_namespace}/${this.group.last_import_target.new_name}` ? `${this.group.last_import_target.target_namespace}/${this.group.last_import_target.new_name}`
: null; : null;
}, },
absoluteLastImportPath() { absoluteLastImportPath() {
return joinPaths(gon.relative_url_root || '/', this.fullLastImportPath); return joinPaths(gon.relative_url_root || '/', this.fullLastImportPath);
}, },
......
...@@ -189,6 +189,24 @@ export default { ...@@ -189,6 +189,24 @@ export default {
}, },
methods: { methods: {
isUnselectable(group) {
return !this.isAvailableForImport(group) || this.isInvalid(group);
},
rowClasses(group) {
const DEFAULT_CLASSES = [
'gl-border-gray-200',
'gl-border-0',
'gl-border-b-1',
'gl-border-solid',
];
const result = [...DEFAULT_CLASSES];
if (this.isUnselectable(group)) {
result.push('gl-cursor-default!');
}
return result;
},
qaRowAttributes(group, type) { qaRowAttributes(group, type) {
if (type === 'row') { if (type === 'row') {
return { return {
...@@ -250,10 +268,7 @@ export default { ...@@ -250,10 +268,7 @@ export default {
const table = this.getTableRef(); const table = this.getTableRef();
this.groups.forEach((group, idx) => { this.groups.forEach((group, idx) => {
if ( if (table.isRowSelected(idx) && this.isUnselectable(group)) {
table.isRowSelected(idx) &&
(!this.isAvailableForImport(group) || this.isInvalid(group))
) {
table.unselectRow(idx); table.unselectRow(idx);
} }
}); });
...@@ -338,7 +353,7 @@ export default { ...@@ -338,7 +353,7 @@ export default {
ref="table" ref="table"
class="gl-w-full" class="gl-w-full"
data-qa-selector="import_table" data-qa-selector="import_table"
tbody-tr-class="gl-border-gray-200 gl-border-0 gl-border-b-1 gl-border-solid" :tbody-tr-class="rowClasses"
:tbody-tr-attr="qaRowAttributes" :tbody-tr-attr="qaRowAttributes"
:items="groups" :items="groups"
:fields="$options.fields" :fields="$options.fields"
......
...@@ -239,8 +239,8 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr ...@@ -239,8 +239,8 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
}); });
}, },
async updateImportStatus(_, { id, status }, { client, getCacheKey }) { async updateImportStatus(_, { id, status: newStatus }, { client, getCacheKey }) {
groupsManager.updateImportProgress(id, status); groupsManager.updateImportProgress(id, newStatus);
const progressItem = client.readFragment({ const progressItem = client.readFragment({
fragment: bulkImportSourceGroupProgressFragment, fragment: bulkImportSourceGroupProgressFragment,
...@@ -251,7 +251,9 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr ...@@ -251,7 +251,9 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
}), }),
}); });
if (status === STATUSES.FINISHED && progressItem && progressItem.status !== status) { const isInProgress = Boolean(progressItem);
const { status: currentStatus } = progressItem ?? {};
if (newStatus === STATUSES.FINISHED && isInProgress && currentStatus !== newStatus) {
const groups = groupsManager.getImportedGroupsByJobId(id); const groups = groupsManager.getImportedGroupsByJobId(id);
groups.forEach(async ({ id: groupId, importTarget }) => { groups.forEach(async ({ id: groupId, importTarget }) => {
...@@ -269,7 +271,7 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr ...@@ -269,7 +271,7 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
return { return {
__typename: clientTypenames.BulkImportProgress, __typename: clientTypenames.BulkImportProgress,
id, id,
status, status: newStatus,
}; };
}, },
......
...@@ -38,10 +38,7 @@ export class SourceGroupsManager { ...@@ -38,10 +38,7 @@ export class SourceGroupsManager {
this.importStates[importId] = { this.importStates[importId] = {
status: jobConfig.status, status: jobConfig.status,
groups: jobConfig.groups.map((g) => ({ groups: jobConfig.groups.map((g) => ({
importTarget: { importTarget: { ...g.import_target },
target_namespace: g.import_target.target_namespace,
new_name: g.import_target.new_name,
},
id: g.id, id: g.id,
})), })),
}; };
......
import { GlButton } from '@gitlab/ui'; import { GlButton, GlIcon } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { STATUSES } from '~/import_entities/constants'; import { STATUSES } from '~/import_entities/constants';
import ImportActionsCell from '~/import_entities/import_groups/components/import_actions_cell.vue'; import ImportActionsCell from '~/import_entities/import_groups/components/import_actions_cell.vue';
...@@ -20,25 +20,44 @@ describe('import actions cell', () => { ...@@ -20,25 +20,44 @@ describe('import actions cell', () => {
wrapper.destroy(); wrapper.destroy();
}); });
it('renders import button when group status is NONE', () => { describe('when import status is NONE', () => {
beforeEach(() => {
const group = generateFakeEntry({ id: 1, status: STATUSES.NONE }); const group = generateFakeEntry({ id: 1, status: STATUSES.NONE });
createComponent({ group }); createComponent({ group });
});
it('renders import button', () => {
const button = wrapper.findComponent(GlButton); const button = wrapper.findComponent(GlButton);
expect(button.exists()).toBe(true); expect(button.exists()).toBe(true);
expect(button.text()).toBe('Import'); expect(button.text()).toBe('Import');
}); });
it('renders re-import button when group status is FINISHED', () => { it('does not render icon with a hint', () => {
expect(wrapper.findComponent(GlIcon).exists()).toBe(false);
});
});
describe('when import status is FINISHED', () => {
beforeEach(() => {
const group = generateFakeEntry({ id: 1, status: STATUSES.FINISHED }); const group = generateFakeEntry({ id: 1, status: STATUSES.FINISHED });
createComponent({ group }); createComponent({ group });
});
it('renders re-import button', () => {
const button = wrapper.findComponent(GlButton); const button = wrapper.findComponent(GlButton);
expect(button.exists()).toBe(true); expect(button.exists()).toBe(true);
expect(button.text()).toBe('Re-import'); expect(button.text()).toBe('Re-import');
}); });
it('renders icon with a hint', () => {
const icon = wrapper.findComponent(GlIcon);
expect(icon.exists()).toBe(true);
expect(icon.attributes().title).toBe(
'Re-import creates a new group. It does not sync with the existing group.',
);
});
});
it('does not render import button when group import is in progress', () => { it('does not render import button when group import is in progress', () => {
const group = generateFakeEntry({ id: 1, status: STATUSES.STARTED }); const group = generateFakeEntry({ id: 1, status: STATUSES.STARTED });
createComponent({ group }); createComponent({ group });
...@@ -47,6 +66,18 @@ describe('import actions cell', () => { ...@@ -47,6 +66,18 @@ describe('import actions cell', () => {
expect(button.exists()).toBe(false); expect(button.exists()).toBe(false);
}); });
it('renders import button as disabled when there are validation errors', () => {
const group = generateFakeEntry({
id: 1,
status: STATUSES.NONE,
validation_errors: [{ field: 'new_name', message: 'something ' }],
});
createComponent({ group });
const button = wrapper.findComponent(GlButton);
expect(button.props().disabled).toBe(true);
});
it('emits import-group event when import button is clicked', () => { it('emits import-group event when import button is clicked', () => {
const group = generateFakeEntry({ id: 1, status: STATUSES.NONE }); const group = generateFakeEntry({ id: 1, status: STATUSES.NONE });
createComponent({ group }); createComponent({ group });
......
...@@ -440,9 +440,10 @@ describe('Bulk import resolvers', () => { ...@@ -440,9 +440,10 @@ describe('Bulk import resolvers', () => {
}, },
}); });
expect(lastImportTarget).toMatchObject(IMPORT_TARGET); expect(lastImportTarget).toStrictEqual(IMPORT_TARGET);
expect(progress).toMatchObject({ expect(progress).toStrictEqual({
__typename: clientTypenames.BulkImportProgress,
id: FAKE_JOB_ID, id: FAKE_JOB_ID,
status: NEW_STATUS, status: NEW_STATUS,
}); });
...@@ -458,7 +459,8 @@ describe('Bulk import resolvers', () => { ...@@ -458,7 +459,8 @@ describe('Bulk import resolvers', () => {
variables: { id: FAKE_JOB_ID, status: NEW_STATUS }, variables: { id: FAKE_JOB_ID, status: NEW_STATUS },
}); });
expect(statusInResponse).toMatchObject({ expect(statusInResponse).toStrictEqual({
__typename: clientTypenames.BulkImportProgress,
id: FAKE_JOB_ID, id: FAKE_JOB_ID,
status: NEW_STATUS, status: NEW_STATUS,
}); });
...@@ -476,7 +478,13 @@ describe('Bulk import resolvers', () => { ...@@ -476,7 +478,13 @@ describe('Bulk import resolvers', () => {
variables: { sourceGroupId: GROUP_ID, field: FAKE_FIELD, message: FAKE_MESSAGE }, variables: { sourceGroupId: GROUP_ID, field: FAKE_FIELD, message: FAKE_MESSAGE },
}); });
expect(validationErrors).toMatchObject([{ field: FAKE_FIELD, message: FAKE_MESSAGE }]); expect(validationErrors).toStrictEqual([
{
__typename: clientTypenames.BulkImportValidationError,
field: FAKE_FIELD,
message: FAKE_MESSAGE,
},
]);
}); });
it('removeValidationError removes error from group', async () => { it('removeValidationError removes error from group', async () => {
...@@ -497,7 +505,7 @@ describe('Bulk import resolvers', () => { ...@@ -497,7 +505,7 @@ describe('Bulk import resolvers', () => {
variables: { sourceGroupId: GROUP_ID, field: FAKE_FIELD }, variables: { sourceGroupId: GROUP_ID, field: FAKE_FIELD },
}); });
expect(validationErrors).toMatchObject([]); expect(validationErrors).toStrictEqual([]);
}); });
}); });
}); });
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