diff --git a/e2e/datagrid-suite/datagrid-data-change.spec.ts b/e2e/datagrid-suite/datagrid-data-change.spec.ts
index f4409e32220..0938b5ebe91 100644
--- a/e2e/datagrid-suite/datagrid-data-change.spec.ts
+++ b/e2e/datagrid-suite/datagrid-data-change.spec.ts
@@ -29,7 +29,7 @@ e2e.scenario({
cy.get('[data-testid="glide-cell-2-1"]').should('have.attr', 'aria-selected', 'true');
cy.get('body').type('12{enter}', { delay: 500 });
- cy.get('[aria-label="Confirm Modal Danger Button"]').click();
+ cy.get('[data-testid="data-testid Confirm Modal Danger Button"]').click();
cy.get('[data-testid="query-editor-row"]').contains('Snapshot');
},
diff --git a/e2e/datagrid-suite/datagrid-editing-features.spec.ts b/e2e/datagrid-suite/datagrid-editing-features.spec.ts
index e71d1f31967..c9bd5d6720b 100644
--- a/e2e/datagrid-suite/datagrid-editing-features.spec.ts
+++ b/e2e/datagrid-suite/datagrid-editing-features.spec.ts
@@ -17,7 +17,7 @@ e2e.scenario({
cy.get('[data-testid="glide-cell-2-1"]').should('have.attr', 'aria-selected', 'true');
cy.get('body').type('123{enter}', { delay: 500 });
- cy.get('[aria-label="Confirm Modal Danger Button"]').click();
+ cy.get('[data-testid="data-testid Confirm Modal Danger Button"]').click();
// Delete a cell
cy.get('.dvn-scroller').click(200, 200);
@@ -57,7 +57,7 @@ e2e.scenario({
cy.get('.dvn-scroller').click(20, 190, { waitForAnimations: true });
cy.get('.dvn-scroller').click(20, 90, { shiftKey: true, waitForAnimations: true }); // with shift to select all rows between clicks
cy.get('body').type('{del}');
- cy.get('[aria-label="Confirm Modal Danger Button"]').click();
+ cy.get('[data-testid="data-testid Confirm Modal Danger Button"]').click();
cy.get('[data-testid="glide-cell-1-4"]').should('have.text', '');
cy.get('[data-testid="glide-cell-1-3"]').should('have.text', '');
cy.get('[data-testid="glide-cell-1-2"]').should('have.text', '');
@@ -72,7 +72,7 @@ e2e.scenario({
cy.get('.dvn-scroller').click(20, 90, { commandKey: true, waitForAnimations: true }); // with cmd to select only clicked rows
cy.get('body').type('{del}');
- cy.get('[aria-label="Confirm Modal Danger Button"]').click();
+ cy.get('[data-testid="data-testid Confirm Modal Danger Button"]').click();
cy.get('[data-testid="glide-cell-1-1"]').should('have.text', '');
cy.get('[data-testid="glide-cell-2-1"]').should('have.text', 0);
@@ -89,7 +89,7 @@ e2e.scenario({
// Delete column through header dropdown menu
cy.get('.dvn-scroller').click(250, 15); // click header dropdown
cy.get('body').click(450, 420); // click delete column
- cy.get('[aria-label="Confirm Modal Danger Button"]').click();
+ cy.get('[data-testid="data-testid Confirm Modal Danger Button"]').click();
cy.get(`[data-testid="${DATAGRID_CANVAS}"] th`).should('have.length', 1);
// Delete row through context menu
@@ -108,7 +108,7 @@ e2e.scenario({
cy.get('.dvn-scroller').click(20, 90, { commandKey: true, waitForAnimations: true }); // with shift to select all rows between clicks
cy.get('.dvn-scroller').rightclick(40, 90);
cy.get('[aria-label="Context menu"]').click(10, 10);
- cy.get('[aria-label="Confirm Modal Danger Button"]').click();
+ cy.get('[data-testid="data-testid Confirm Modal Danger Button"]').click();
cy.get(`[data-testid="${DATAGRID_CANVAS}"] tbody tr`).should('have.length', 5); // there are 5 data rows + 1 for the add new row btns
// Delete column through context menu
@@ -121,7 +121,7 @@ e2e.scenario({
// Add a new column
cy.get('body').click(350, 200).type('New Column{enter}');
- cy.get('[aria-label="Confirm Modal Danger Button"]').click();
+ cy.get('[data-testid="data-testid Confirm Modal Danger Button"]').click();
cy.get('body')
.click(350, 230)
.type('Value 1{enter}')
@@ -138,7 +138,7 @@ e2e.scenario({
cy.get(`[data-testid="${DATAGRID_CANVAS}"] th`).contains('Renamed column');
// Change column field type
- cy.get('.dvn-scroller').click(250, 15);
+ cy.get('.dvn-scroller').click(310, 15);
cy.get('[aria-label="Context menu"]').click(50, 50);
cy.get('.dvn-scroller').click(200, 100);
cy.get('body').type('Str Value{enter}');
diff --git a/public/app/plugins/panel/datagrid/DataGridPanel.test.tsx b/public/app/plugins/panel/datagrid/DataGridPanel.test.tsx
index d2e13269bf7..1b7ff145e54 100644
--- a/public/app/plugins/panel/datagrid/DataGridPanel.test.tsx
+++ b/public/app/plugins/panel/datagrid/DataGridPanel.test.tsx
@@ -111,14 +111,28 @@ describe('DataGrid', () => {
expect(screen.getByText('Remove all data')).toBeInTheDocument();
expect(screen.getByText('Search...')).toBeInTheDocument();
- // click on header cell should show only column options
+ // right clicking on header cell without clicking/selecting the cell should show only general options
+ fireEvent.contextMenu(scroller, {
+ clientX: 50,
+ clientY: 36,
+ });
+
+ expect(screen.getByText('Remove all data')).toBeInTheDocument();
+ expect(screen.getByText('Search...')).toBeInTheDocument();
+
+ // selecting the header first and then right click on header cell should show only column options
+ const canvas = screen.getByTestId('data-grid-canvas');
+ sendClick(canvas, {
+ clientX: 50,
+ clientY: 36,
+ });
+
fireEvent.contextMenu(scroller, {
clientX: 50,
clientY: 36,
});
expect(screen.getByText('Delete column')).toBeInTheDocument();
- expect(screen.getByText('Clear column')).toBeInTheDocument();
expect(screen.getByText('Remove all data')).toBeInTheDocument();
expect(screen.getByText('Search...')).toBeInTheDocument();
diff --git a/public/app/plugins/panel/datagrid/DataGridPanel.tsx b/public/app/plugins/panel/datagrid/DataGridPanel.tsx
index a79fc9f45c6..679049e51da 100644
--- a/public/app/plugins/panel/datagrid/DataGridPanel.tsx
+++ b/public/app/plugins/panel/datagrid/DataGridPanel.tsx
@@ -154,8 +154,29 @@ export function DataGridPanel({ options, data, id, fieldConfig, width, height }:
return true;
}
- if (selection.rows) {
- updateSnapshot(deleteRows(frame, selection.rows.toArray()), onUpdateData);
+ const rows = selection.rows.toArray();
+ const cols = selection.columns.toArray();
+
+ if (rows.length) {
+ updateSnapshot(deleteRows(frame, rows), onUpdateData);
+ return true;
+ }
+
+ if (cols.length) {
+ const copiedFrame = {
+ ...frame,
+ fields: frame.fields.map((field, index) => {
+ if (cols.includes(index)) {
+ return {
+ ...field,
+ values: new Array(frame.length).fill(null),
+ };
+ }
+
+ return field;
+ }),
+ };
+ updateSnapshot(copiedFrame, onUpdateData);
return true;
}
diff --git a/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx b/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx
index 648fbd45160..697f5bdfa01 100644
--- a/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx
+++ b/public/app/plugins/panel/datagrid/components/DatagridContextMenu.tsx
@@ -53,10 +53,11 @@ export const DatagridContextMenu = ({
columnDeletionLabel = `Delete ${selectedColumns.length} columns`;
}
+ // Show delete/clear options on cell right click, but not on header right click, unless header column is specifically selected.
const showDeleteRow = (row !== undefined && row >= 0) || selectedRows.length;
- const showDeleteColumn = (column !== undefined && column >= 0) || selectedColumns.length;
+ const showDeleteColumn = (column !== undefined && column >= 0 && row !== undefined) || selectedColumns.length;
const showClearRow = row !== undefined && row >= 0 && !selectedRows.length;
- const showClearColumn = column !== undefined && column >= 0 && !selectedColumns.length;
+ const showClearColumn = column !== undefined && column >= 0 && row !== undefined && !selectedColumns.length;
const renderContextMenuItems = () => (
<>
@@ -85,6 +86,7 @@ export const DatagridContextMenu = ({
...data,
fields: data.fields.filter((_, index) => !selectedColumns.includes(index)),
});
+ dispatch({ type: DatagridActionType.gridSelectionCleared });
return;
}
@@ -215,20 +217,25 @@ export const DatagridContextMenu = ({