;
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();
},
diff --git a/packages/frontend/editor-ui/src/components/executions/global/GlobalExecutionsList.vue b/packages/frontend/editor-ui/src/components/executions/global/GlobalExecutionsList.vue
index 3ffcd91f0c..a3fe99fd96 100644
--- a/packages/frontend/editor-ui/src/components/executions/global/GlobalExecutionsList.vue
+++ b/packages/frontend/editor-ui/src/components/executions/global/GlobalExecutionsList.vue
@@ -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 = () => {
-
-
- {{
- i18n.baseText('executionsList.selected', {
- adjustToNumber: selectedCount,
- interpolate: { count: `${selectedCount}` },
- })
- }}
-
-
-
-
+
@@ -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;
diff --git a/packages/frontend/editor-ui/src/features/dataStore/components/dataGrid/DataStoreTable.vue b/packages/frontend/editor-ui/src/features/dataStore/components/dataGrid/DataStoreTable.vue
index 22607d0a07..05ba1cc611 100644
--- a/packages/frontend/editor-ui/src/features/dataStore/components/dataGrid/DataStoreTable.vue
+++ b/packages/frontend/editor-ui/src/features/dataStore/components/dataGrid/DataStoreTable.vue
@@ -1,5 +1,5 @@
@@ -504,7 +572,7 @@ const onCellEditingStopped = (params: CellEditingStoppedEvent) =>
@cell-editing-started="onCellEditingStarted"
@cell-editing-stopped="onCellEditingStopped"
@column-header-clicked="resetLastFocusedCell"
- @selection-changed="resetLastFocusedCell"
+ @selection-changed="onSelectionChanged"
/>
) =>
@size-change="setPageSize"
/>
+
diff --git a/packages/frontend/editor-ui/src/features/dataStore/dataStore.api.test.ts b/packages/frontend/editor-ui/src/features/dataStore/dataStore.api.test.ts
new file mode 100644
index 0000000000..38cb4fc8af
--- /dev/null
+++ b/packages/frontend/editor-ui/src/features/dataStore/dataStore.api.test.ts
@@ -0,0 +1,40 @@
+import { deleteDataStoreRowsApi } from '@/features/dataStore/dataStore.api';
+import { makeRestApiRequest } from '@n8n/rest-api-client';
+import { expect } from 'vitest';
+
+vi.mock('@n8n/rest-api-client', () => ({
+ makeRestApiRequest: vi.fn(),
+}));
+
+describe('dataStore.api', () => {
+ afterEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe('deleteDataStoreRowsApi', () => {
+ it('should make DELETE request with correct parameters', async () => {
+ const dataStoreId = 'test-datastore-id';
+ const projectId = 'test-project-id';
+ const rowIds = [1, 2, 3];
+
+ vi.mocked(makeRestApiRequest).mockResolvedValue(true);
+
+ const result = await deleteDataStoreRowsApi(
+ { baseUrl: '/rest', pushRef: 'test-push-ref' },
+ dataStoreId,
+ rowIds,
+ projectId,
+ );
+
+ expect(makeRestApiRequest).toHaveBeenCalledWith(
+ expect.anything(),
+ 'DELETE',
+ `/projects/${projectId}/data-stores/${dataStoreId}/rows`,
+ {
+ ids: '1,2,3',
+ },
+ );
+ expect(result).toBe(true);
+ });
+ });
+});
diff --git a/packages/frontend/editor-ui/src/features/dataStore/dataStore.api.ts b/packages/frontend/editor-ui/src/features/dataStore/dataStore.api.ts
index 7ede5522fb..44de0423b6 100644
--- a/packages/frontend/editor-ui/src/features/dataStore/dataStore.api.ts
+++ b/packages/frontend/editor-ui/src/features/dataStore/dataStore.api.ts
@@ -178,3 +178,19 @@ export const updateDataStoreRowsApi = async (
},
);
};
+
+export const deleteDataStoreRowsApi = async (
+ context: IRestApiContext,
+ dataStoreId: string,
+ rowIds: number[],
+ projectId: string,
+) => {
+ return await makeRestApiRequest(
+ context,
+ 'DELETE',
+ `/projects/${projectId}/data-stores/${dataStoreId}/rows`,
+ {
+ ids: rowIds.join(','),
+ },
+ );
+};
diff --git a/packages/frontend/editor-ui/src/features/dataStore/dataStore.store.test.ts b/packages/frontend/editor-ui/src/features/dataStore/dataStore.store.test.ts
index d5755f21ec..819850bf48 100644
--- a/packages/frontend/editor-ui/src/features/dataStore/dataStore.store.test.ts
+++ b/packages/frontend/editor-ui/src/features/dataStore/dataStore.store.test.ts
@@ -89,4 +89,22 @@ describe('dataStore.store', () => {
);
expect(dataStoreStore.dataStores[0].columns.find((c) => c.id === columnId)).toBeUndefined();
});
+
+ it('can delete rows', async () => {
+ const datastoreId = faker.string.alphanumeric(10);
+ const projectId = 'p1';
+ const rowIds = [1, 2, 3];
+
+ vi.spyOn(dataStoreApi, 'deleteDataStoreRowsApi').mockResolvedValue(true);
+
+ const result = await dataStoreStore.deleteRows(datastoreId, projectId, rowIds);
+
+ expect(result).toBe(true);
+ expect(dataStoreApi.deleteDataStoreRowsApi).toHaveBeenCalledWith(
+ rootStore.restApiContext,
+ datastoreId,
+ rowIds,
+ projectId,
+ );
+ });
});
diff --git a/packages/frontend/editor-ui/src/features/dataStore/dataStore.store.ts b/packages/frontend/editor-ui/src/features/dataStore/dataStore.store.ts
index eee4877323..7b783ee83c 100644
--- a/packages/frontend/editor-ui/src/features/dataStore/dataStore.store.ts
+++ b/packages/frontend/editor-ui/src/features/dataStore/dataStore.store.ts
@@ -13,6 +13,7 @@ import {
getDataStoreRowsApi,
insertDataStoreRowApi,
updateDataStoreRowsApi,
+ deleteDataStoreRowsApi,
} from '@/features/dataStore/dataStore.api';
import type {
DataStore,
@@ -208,6 +209,10 @@ export const useDataStoreStore = defineStore(DATA_STORE_STORE, () => {
);
};
+ const deleteRows = async (dataStoreId: string, projectId: string, rowIds: number[]) => {
+ return await deleteDataStoreRowsApi(rootStore.restApiContext, dataStoreId, rowIds, projectId);
+ };
+
return {
dataStores,
totalCount,
@@ -223,5 +228,6 @@ export const useDataStoreStore = defineStore(DATA_STORE_STORE, () => {
fetchDataStoreContent,
insertEmptyRow,
updateRow,
+ deleteRows,
};
});