mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-18 10:31:15 +00:00
feat(editor): Implement delete datastore row UI (no-changelog) (#18729)
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import { createComponentRenderer } from '@/__tests__/render';
|
||||
import SelectedItemsInfo from '@/components/common/SelectedItemsInfo.vue';
|
||||
|
||||
const renderComponent = createComponentRenderer(SelectedItemsInfo);
|
||||
|
||||
vi.mock('@n8n/i18n', async (importOriginal) => ({
|
||||
...(await importOriginal()),
|
||||
useI18n: () => ({
|
||||
baseText: (key: string) => key,
|
||||
}),
|
||||
}));
|
||||
|
||||
describe('SelectedItemsInfo', () => {
|
||||
it('should not render when selectedCount is 0', () => {
|
||||
const { queryByTestId } = renderComponent({
|
||||
props: {
|
||||
selectedCount: 0,
|
||||
},
|
||||
});
|
||||
|
||||
expect(queryByTestId('selected-items-info')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render when selectedCount is greater than 0', () => {
|
||||
const { getByTestId } = renderComponent({
|
||||
props: {
|
||||
selectedCount: 3,
|
||||
},
|
||||
});
|
||||
|
||||
expect(getByTestId('selected-items-info')).toBeInTheDocument();
|
||||
expect(getByTestId('delete-selected-button')).toBeInTheDocument();
|
||||
expect(getByTestId('clear-selection-button')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should emit deleteSelected event when delete button is clicked', () => {
|
||||
const { getByTestId, emitted } = renderComponent({
|
||||
props: {
|
||||
selectedCount: 1,
|
||||
},
|
||||
});
|
||||
|
||||
getByTestId('delete-selected-button').click();
|
||||
|
||||
expect(emitted().deleteSelected).toBeTruthy();
|
||||
expect(emitted().deleteSelected).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should emit clearSelection event when clear button is clicked', () => {
|
||||
const { getByTestId, emitted } = renderComponent({
|
||||
props: {
|
||||
selectedCount: 5,
|
||||
},
|
||||
});
|
||||
|
||||
getByTestId('clear-selection-button').click();
|
||||
|
||||
expect(emitted().clearSelection).toBeTruthy();
|
||||
expect(emitted().clearSelection).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
import { N8nButton } from '@n8n/design-system';
|
||||
|
||||
interface Props {
|
||||
selectedCount: number;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
|
||||
const emit = defineEmits<{
|
||||
deleteSelected: [];
|
||||
clearSelection: [];
|
||||
}>();
|
||||
|
||||
const i18n = useI18n();
|
||||
|
||||
const getSelectedText = () => {
|
||||
return i18n.baseText('generic.list.selected', {
|
||||
adjustToNumber: props.selectedCount,
|
||||
interpolate: { count: `${props.selectedCount}` },
|
||||
});
|
||||
};
|
||||
|
||||
const getClearSelectionText = () => {
|
||||
return i18n.baseText('generic.list.clearSelection');
|
||||
};
|
||||
|
||||
const handleDeleteSelected = () => {
|
||||
emit('deleteSelected');
|
||||
};
|
||||
|
||||
const handleClearSelection = () => {
|
||||
emit('clearSelection');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
v-if="selectedCount > 0"
|
||||
:class="$style.selectionOptions"
|
||||
:data-test-id="`selected-items-info`"
|
||||
>
|
||||
<span>
|
||||
{{ getSelectedText() }}
|
||||
</span>
|
||||
<N8nButton
|
||||
:label="i18n.baseText('generic.delete')"
|
||||
type="tertiary"
|
||||
data-test-id="delete-selected-button"
|
||||
@click="handleDeleteSelected"
|
||||
/>
|
||||
<N8nButton
|
||||
:label="getClearSelectionText()"
|
||||
type="tertiary"
|
||||
data-test-id="clear-selection-button"
|
||||
@click="handleClearSelection"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style module lang="scss">
|
||||
.selectionOptions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
padding: var(--spacing-2xs);
|
||||
z-index: 2;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: var(--spacing-3xl);
|
||||
background: var(--execution-selector-background);
|
||||
border-radius: var(--border-radius-base);
|
||||
color: var(--execution-selector-text);
|
||||
font-size: var(--font-size-2xs);
|
||||
|
||||
button {
|
||||
margin-left: var(--spacing-2xs);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -26,6 +26,23 @@ vi.mock('vue-router', () => ({
|
||||
RouterLink: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@n8n/i18n', async (importOriginal) => ({
|
||||
...(await importOriginal()),
|
||||
useI18n: () => ({
|
||||
displayTimer: (timer: number) => timer,
|
||||
baseText: (key: string, options: { interpolate: { count: string } }) => {
|
||||
if (key === 'generic.list.selected') {
|
||||
return `${options.interpolate.count} executions selected`;
|
||||
} else if (key === 'executionsList.retryOf') {
|
||||
return 'Retry of';
|
||||
} else if (key === 'executionsList.successRetry') {
|
||||
return 'Success retry';
|
||||
}
|
||||
return key;
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
let settingsStore: MockedStore<typeof useSettingsStore>;
|
||||
|
||||
const generateUndefinedNullOrString = () => {
|
||||
@@ -148,7 +165,7 @@ describe('GlobalExecutionsList', () => {
|
||||
).toBe(10),
|
||||
);
|
||||
expect(getByTestId('select-all-executions-checkbox')).toBeInTheDocument();
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(10);
|
||||
expect(getByTestId('selected-items-info').textContent).toContain(10);
|
||||
|
||||
await userEvent.click(getByTestId('load-more-button'));
|
||||
await rerender({
|
||||
@@ -170,7 +187,7 @@ describe('GlobalExecutionsList', () => {
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(20);
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(20);
|
||||
expect(getByTestId('selected-items-info').textContent).toContain(20);
|
||||
|
||||
await userEvent.click(getAllByTestId('select-execution-checkbox')[2]);
|
||||
expect(getAllByTestId('select-execution-checkbox').length).toBe(20);
|
||||
@@ -179,7 +196,7 @@ describe('GlobalExecutionsList', () => {
|
||||
el.contains(el.querySelector(':checked')),
|
||||
).length,
|
||||
).toBe(19);
|
||||
expect(getByTestId('selected-executions-info').textContent).toContain(19);
|
||||
expect(getByTestId('selected-items-info').textContent).toContain(19);
|
||||
expect(getByTestId('select-visible-executions-checkbox')).toBeInTheDocument();
|
||||
expect(queryByTestId('select-all-executions-checkbox')).not.toBeInTheDocument();
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import ConcurrentExecutionsHeader from '@/components/executions/ConcurrentExecutionsHeader.vue';
|
||||
import ExecutionsFilter from '@/components/executions/ExecutionsFilter.vue';
|
||||
import GlobalExecutionsListItem from '@/components/executions/global/GlobalExecutionsListItem.vue';
|
||||
import SelectedItemsInfo from '@/components/common/SelectedItemsInfo.vue';
|
||||
import { useI18n } from '@n8n/i18n';
|
||||
import { useMessage } from '@/composables/useMessage';
|
||||
import { usePageRedirectionHelper } from '@/composables/usePageRedirectionHelper';
|
||||
@@ -455,32 +456,11 @@ const goToUpgrade = () => {
|
||||
</N8nTableBase>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="selectedCount > 0"
|
||||
:class="$style.selectionOptions"
|
||||
data-test-id="selected-executions-info"
|
||||
>
|
||||
<span>
|
||||
{{
|
||||
i18n.baseText('executionsList.selected', {
|
||||
adjustToNumber: selectedCount,
|
||||
interpolate: { count: `${selectedCount}` },
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<N8nButton
|
||||
:label="i18n.baseText('generic.delete')"
|
||||
type="tertiary"
|
||||
data-test-id="delete-selected-button"
|
||||
@click="handleDeleteSelected"
|
||||
/>
|
||||
<N8nButton
|
||||
:label="i18n.baseText('executionsList.clearSelection')"
|
||||
type="tertiary"
|
||||
data-test-id="clear-selection-button"
|
||||
@click="handleClearSelection"
|
||||
/>
|
||||
</div>
|
||||
<SelectedItemsInfo
|
||||
:selected-count="selectedCount"
|
||||
@delete-selected="handleDeleteSelected"
|
||||
@clear-selection="handleClearSelection"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -507,25 +487,6 @@ const goToUpgrade = () => {
|
||||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
|
||||
.selectionOptions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
padding: var(--spacing-2xs);
|
||||
z-index: 2;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: var(--spacing-3xl);
|
||||
background: var(--execution-selector-background);
|
||||
border-radius: var(--border-radius-base);
|
||||
color: var(--execution-selector-text);
|
||||
font-size: var(--font-size-2xs);
|
||||
|
||||
button {
|
||||
margin-left: var(--spacing-2xs);
|
||||
}
|
||||
}
|
||||
|
||||
.execTable {
|
||||
height: 100%;
|
||||
flex: 0 1 auto;
|
||||
|
||||
Reference in New Issue
Block a user