Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Saved object refactoring for panels #355

Merged
merged 13 commits into from
Apr 14, 2023
Merged
Binary file added .cypress/.DS_Store
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,6 @@ import {

import { suppressResizeObserverIssue } from '../utils/constants';

const moveToEventsHome = () => {
cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics/`);
cy.wait(delay * 3);
};

const moveToPanelHome = () => {
cy.visit(
`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/`
);
cy.wait(delay * 3);
};

const moveToTestPanel = () => {
moveToPanelHome();
cy.get('.euiTableCellContent').contains(TEST_PANEL).trigger('mouseover').click();
cy.wait(delay * 3);
cy.get('h1').contains(TEST_PANEL).should('exist');
};

describe('Adding sample data and visualization', () => {
it('Adds sample flights data for visualization paragraph', () => {
Expand Down Expand Up @@ -96,44 +78,78 @@ describe('Creating visualizations', () => {
});
});

describe('Testing panels table', () => {
describe.only('Testing panels table', () => {
beforeEach(() => {
moveToPanelHome();
eraseTestPanels();
});

it('Displays error toast for invalid panel name', () => {
cy.get('button[data-test-subj="customPanels__createNewPanels"]').click();
cy.get('button[data-test-subj="runModalButton"]').click();
cy.get('.euiToastHeader__title').contains('Invalid Operational Panel name').should('exist');
clickCreatePanelButton();
confirmModal();
expectToastWith('Invalid Operational Panel name');
});

it('Creates a panel and redirects to the panel', () => {
cy.get('button[data-test-subj="customPanels__createNewPanels"]').click();
clickCreatePanelButton();
cy.get('input.euiFieldText').focus().type(TEST_PANEL, {
delay: 50,
});
cy.get('button[data-test-subj="runModalButton"]').click();
cy.contains(TEST_PANEL).should('exist');
});

it('Duplicates a panel', () => {
cy.get('.euiCheckbox__input[title="Select this row"]').eq(0).trigger('mouseover').click();
cy.get('button[data-test-subj="operationalPanelsActionsButton"]').click();
it('Duplicates a legacy panel', () => {
createLegacyPanel()
selectThePanel();
openActionsDropdown();
cy.get('button[data-test-subj="duplicateContextMenuItem"]').click();
cy.get('button[data-test-subj="runModalButton"]').click();
cy.contains(TEST_PANEL + " (copy)").should('exist');
const duplicate = testPanelTableCell()
expectUuid(duplicate)
});

it('Renames a panel', () => {
cy.get('.euiCheckbox__input[title="Select this row"]').eq(0).trigger('mouseover').click();
cy.get('button[data-test-subj="operationalPanelsActionsButton"]').click();
it.only('Duplicates a legacy panel', () => {
createLegacyPanel()
selectThePanel();
openActionsDropdown();
cy.get('button[data-test-subj="duplicateContextMenuItem"]').click();
cy.get('button[data-test-subj="runModalButton"]').click();
cy.contains(TEST_PANEL + " (copy)").should('exist');
const duplicate = testPanelTableCell()
expectUuid(duplicate)
});

it('Renames a saved-objects panel', () => {
createSavedObjectPanel()
cy.reload()

selectThePanel()
openActionsDropdown();
cy.get('button[data-test-subj="renameContextMenuItem"]').click();
cy.get('input.euiFieldText').focus().type(' (rename)', {
delay: 50,
});
cy.get('button[data-test-subj="runModalButton"]').click();
});

it('Renames a panel', () => {
createLegacyPanel();
cy.reload();
const cell = cy.get('.euiTableCellContent')
expectLegacyId(cell);
selectThePanel()
openActionsDropdown();
cy.get('button[data-test-subj="renameContextMenuItem"]').click();
cy.get('input.euiFieldText').focus().type(' (rename)');
cy.get('button[data-test-subj="runModalButton"]').click();
const renamed = testPanelTableCell()
expectUuid(renamed)
});

it('Searches existing panel', () => {
createLegacyPanel()
cy.get('input[data-test-subj="operationalPanelSearchBar"]')
.focus()
.type('this panel should not exist', {
Expand All @@ -154,9 +170,24 @@ describe('Testing panels table', () => {
.should('exist');
});

it('Deletes saved object panels', () => {
createSavedObjectPanel()
cy.get('input[data-test-subj="checkboxSelectAll"]').click();
openActionsDropdown();
cy.get('button[data-test-subj="deleteContextMenuItem"]').click();
cy.get('button[data-test-subj="popoverModal__deleteButton"]').should('be.disabled');

cy.get('input.euiFieldText[placeholder="delete"]').focus().type('delete', {
delay: 50,
});
cy.get('button[data-test-subj="popoverModal__deleteButton"]').should('not.be.disabled');
cy.get('button[data-test-subj="popoverModal__deleteButton"]').click();
cy.get('h2[data-test-subj="customPanels__noPanelsHome"]').should('exist');
});

it('Deletes panels', () => {
cy.get('input[data-test-subj="checkboxSelectAll"]').click();
cy.get('button[data-test-subj="operationalPanelsActionsButton"]').click();
openActionsDropdown();
cy.get('button[data-test-subj="deleteContextMenuItem"]').click();
cy.get('button[data-test-subj="popoverModal__deleteButton"]').should('be.disabled');

Expand All @@ -170,7 +201,7 @@ describe('Testing panels table', () => {

it('Create a panel for testing', () => {
// keep a panel for testing
cy.get('button[data-test-subj="customPanels__createNewPanels"]').click();
clickCreatePanelButton();
cy.get('input.euiFieldText').focus().type(TEST_PANEL, {
delay: 50,
});
Expand Down Expand Up @@ -470,8 +501,8 @@ describe('Clean up all test data', () => {
it('Deletes test panel', () => {
moveToPanelHome();
cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]').trigger('mouseover').click();
cy.get('button[data-test-subj="operationalPanelsActionsButton"]').click();
cy.get('button[data-test-subj="deleteContextMenuItem"]').click();
openActionsDropdown();
clickDeleteAction();
cy.get('button.euiButton--danger').should('be.disabled');
cy.get('input.euiFieldText[placeholder="delete"]').focus().type('delete', {
delay: 50,
Expand All @@ -482,3 +513,169 @@ describe('Clean up all test data', () => {
cy.get('.euiTextAlign').contains('No Operational Panels').should('exist');
});
});


const moveToEventsHome = () => {
cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/event_analytics/`);
cy.wait(delay * 3);
};

const moveToPanelHome = () => {
cy.visit(
`${Cypress.env('opensearchDashboards')}/app/observability-dashboards#/operational_panels/`
, { timeout: 3000 });
cy.wait(delay * 3);
};

const testPanelTableCell = () => cy.get('.euiTableCellContent').contains(TEST_PANEL)

const moveToTestPanel = () => {
moveToPanelHome();
testPanelTableCell().trigger('mouseover').click();
cy.wait(delay * 3);
cy.get('h1').contains(TEST_PANEL).should('exist');
};

const TEST_PANEL_RX = new RegExp(TEST_PANEL + '.*')

const eraseLegacyPanels = () => {

cy.request({
method: 'GET',
failOnStatusCode: false,
url: 'api/observability/operational_panels/panels',
headers: {
'content-type': 'application/json;charset=UTF-8',
'osd-xsrf': true,
},
}).then((response) => {
response.body.panels
.map(panel => {
cy.request({
method: 'DELETE',
failOnStatusCode: false,
url: `api/observability/operational_panels/panels/${panel.id}`,
headers: {
'content-type': 'application/json;charset=UTF-8',
'osd-xsrf': true,
}
}).then(response => {
const deletedId = response.allRequestResponses[0]['Request URL'].split('/').slice(-1)
console.log("erased panel", deletedId)
})
}
)
}
)
}

const eraseSavedObjectPaenls = () => {
return cy.request({
method: 'get',
failOnStatusCode: false,
url: 'api/saved_objects/_find?type=observability-panel',
headers: {
'content-type': 'application/json;charset=UTF-8',
'osd-xsrf': true,
}
}).then(response => {
response.body.saved_objects
.map(soPanel => {
cy.request({
method: 'DELETE',
failOnStatusCode: false,
url: `api/saved_objects/observability-panel/${soPanel.id}`,
headers: {
'content-type': 'application/json;charset=UTF-8',
'osd-xsrf': true,
}
})
})
})
}

const eraseTestPanels = () => {
eraseLegacyPanels()
eraseSavedObjectPaenls()

}
const uuidRx = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/;

const clickCreatePanelButton = () => cy.get('a[data-test-subj="customPanels__createNewPanels"]').click();

const createSavedObjectPanel = () => {
const result = cy.request({
method: 'POST',
failOnStatusCode: false,
url: 'api/saved_objects/observability-panel',
headers: {
'content-type': 'application/json;charset=UTF-8',
'osd-xsrf': true,
},
body: {
"attributes": {
"title": TEST_PANEL,
"description": "",
"dateCreated": 1681127334085,
"dateModified": 1681127334085,
"timeRange": {
"to": "now",
"from": "now-1d"
},
"queryFilter": {
"query": "",
"language": "ppl"
},
"visualizations": [],
"applicationId": ""
}
}
}).then(response => console.log(response))

}

const createLegacyPanel = () => {
const result = cy.request({
method: 'POST',
failOnStatusCode: false,
url: 'api/observability/operational_panels/panels',
headers: {
'content-type': 'application/json;charset=UTF-8',
'osd-xsrf': true,
},
body: { panelName: TEST_PANEL }
})
}

const expectUuid = (cell) => {
cell.find('a').its('href').should('match', uuidRx)
// const id = url.split('/').slice(-1)
// expect(id).not.to.match(uuidRx)
}

const expectLegacyId = (cell) => {
cell.find('a').its('href').should('not.match', uuidRx)
// const id = url.split('/').slice(-1)
// expect(id).not.to.match(uuidRx)
}

const clickDeleteAction = () => {
cy.get('button[data-test-subj="deleteContextMenuItem"]').click();
}

const openActionsDropdown = () => {
cy.get('button[data-test-subj="operationalPanelsActionsButton"]').click();
}

const selectThePanel = () => {
cy.get('.euiCheckbox__input[title="Select this row"]').eq(0).trigger('mouseover').click();
}

const expectToastWith = (title) => {
cy.get('.euiToastHeader__title').contains(title).should('exist');
}

const confirmModal = () => {
cy.get('button[data-test-subj="runModalButton"]').click();
}

4 changes: 4 additions & 0 deletions .cypress/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)


/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
require('cypress-watch-and-reload/plugins')(config)

return config
}
2 changes: 2 additions & 0 deletions .cypress/support/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
// https://on.cypress.io/configuration
// ***********************************************************

import 'cypress-watch-and-reload/support'

// Import commands.js using ES2015 syntax:
import './commands';

Expand Down
7 changes: 6 additions & 1 deletion common/constants/custom_panels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,10 @@
*/

export const CUSTOM_PANELS_API_PREFIX = '/api/observability/operational_panels';
export const CUSTOM_PANELS_DOCUMENTATION_URL = 'https://opensearch.org/docs/latest/observability-plugin/operational-panels/';
export const CUSTOM_PANELS_DOCUMENTATION_URL =
'https://opensearch.org/docs/latest/observability-plugin/operational-panels/';
export const CREATE_PANEL_MESSAGE = 'Enter a name to describe the purpose of this custom panel.';

export const CUSTOM_PANELS_SAVED_OBJECT_TYPE = 'observability-panel';

export const CUSTOM_PANEL_SLICE = 'customPanel';
Loading