Skip to content

Commit

Permalink
[Feature] Saved object refactoring for panels (#355)
Browse files Browse the repository at this point in the history
* Operational Panels Integrate with Dashboards-List

---------

Signed-off-by: Peter Fitzgibbons <[email protected]>
Signed-off-by: Derek Ho <[email protected]>
Signed-off-by: Eric Wei <[email protected]>
Co-authored-by: Peter Fitzgibbons <[email protected]>
Co-authored-by: Derek Ho <[email protected]>

(cherry picked from commit 775a77e)
Signed-off-by: Peter Fitzgibbons <[email protected]>
  • Loading branch information
3 people committed Apr 18, 2023
1 parent 03bdf6d commit bc792b7
Show file tree
Hide file tree
Showing 27 changed files with 2,527 additions and 273 deletions.
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

0 comments on commit bc792b7

Please sign in to comment.