Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 51 additions & 8 deletions .cypress/integration/2_notebooks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import { SAMPLE_PANEL } from '../utils/panel_constants';

import { skipOn } from '@cypress/skip-test';

import { v4 as uuid4 } from 'uuid';

const moveToEventsHome = () => {
cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-logs#/`);
};
Expand Down Expand Up @@ -157,7 +159,7 @@ describe('Test reporting integration if plugin installed', () => {
beforeEach(() => {
cy.visit(`${Cypress.env('opensearchDashboards')}/app/observability-notebooks#/`);
cy.get('.euiTableCellContent').contains(TEST_NOTEBOOK).click();
cy.wait(delay);//page needs to process before checking
cy.wait(delay); //page needs to process before checking
cy.get('body').then(($body) => {
skipOn($body.find('#reportingActionsButton').length <= 0);
});
Expand Down Expand Up @@ -290,8 +292,9 @@ describe('Testing paragraphs', () => {

it('Adds a SQL query paragraph', () => {
cy.contains('Add paragraph').click();
cy.get('.euiContextMenuItem__text').contains('Code block').click(), { timeout: COMMAND_TIMEOUT_LONG };
cy.wait(delay);//SQL_QUERY_TEXT will sometimes fail to type without this delay
cy.get('.euiContextMenuItem__text').contains('Code block').click(),
{ timeout: COMMAND_TIMEOUT_LONG };
cy.wait(delay); //SQL_QUERY_TEXT will sometimes fail to type without this delay

cy.get('.euiTextArea').type(SQL_QUERY_TEXT);
cy.get('.euiButton__text').contains('Run').click();
Expand All @@ -301,6 +304,45 @@ describe('Testing paragraphs', () => {
cy.get('.euiDataGrid__overflow').should('exist');
});

it('Renders very long markdown as wrapped', () => {
cy.contains('Add paragraph').click();
cy.get('.euiContextMenuItem__text').contains('Code block').click(),
{ timeout: COMMAND_TIMEOUT_LONG };
cy.wait(delay); //SQL_QUERY_TEXT will sometimes fail to type without this delay

const testWord = uuid4().replace(/-/gi, '').repeat(10);
cy.get('.euiTextArea').type(`%md\n${testWord}`);
cy.get('.euiButton__text').contains('Run').click();

cy.get('p')
.contains(testWord)
.then((element) => {
const clientWidth = element[0].clientWidth;
const scrollWidth = element[0].scrollWidth;
console.log('paragraph', { clientWidth, scrollWidth });
expect(scrollWidth, 'Output Text has not been wrapped').to.be.at.most(clientWidth);
});
});

it('Renders very long query as wrapped', () => {
cy.contains('Add paragraph').click();
cy.get('.euiContextMenuItem__text').contains('Code block').click(),
{ timeout: COMMAND_TIMEOUT_LONG };
cy.wait(delay); //SQL_QUERY_TEXT will sometimes fail to type without this delay

const testWord = uuid4().replace(/-/gi, '').repeat(10);
cy.get('.euiTextArea').type(`%sql\nSELECT 1 AS ${testWord}`);
cy.get('.euiButton__text').contains('Run').click();

cy.get('b')
.contains(testWord)
.then((element) => {
const clientWidth = element[0].clientWidth;
const scrollWidth = element[0].scrollWidth;
expect(scrollWidth, 'Output Text has not been wrapped').to.be.at.most(clientWidth);
});
});

it('Adds an observability visualization paragraph', () => {
cy.contains('Add paragraph').click();
cy.get('.euiContextMenuItem__text').contains('Visualization').click();
Expand All @@ -319,8 +361,9 @@ describe('Testing paragraphs', () => {

it('Adds a PPL query paragraph', () => {
cy.contains('Add paragraph').click();
cy.get('.euiContextMenuItem__text').contains('Code block').click(), { timeout: COMMAND_TIMEOUT_LONG };;
cy.wait(delay);//PPL_QUERY_TEXT will sometimes fail to type without this delay
cy.get('.euiContextMenuItem__text').contains('Code block').click(),
{ timeout: COMMAND_TIMEOUT_LONG };
cy.wait(delay); //PPL_QUERY_TEXT will sometimes fail to type without this delay

cy.get('.euiTextArea').type(PPL_QUERY_TEXT);
cy.get('.euiButton__text').contains('Run').click();
Expand Down Expand Up @@ -433,7 +476,7 @@ describe('clean up all test data', () => {
cy.get('.euiButton__text').contains('Actions').trigger('mouseover').click();
cy.get('.euiContextMenuItem__text').contains('Delete').trigger('mouseover').click();
cy.get('button.euiButton--danger').should('be.disabled');
cy.get('input.euiFieldText[placeholder="delete"]').focus().type('delete', {delay: 50, });
cy.get('input.euiFieldText[placeholder="delete"]').focus().type('delete', { delay: 50 });
cy.get('button.euiButton--danger').should('not.be.disabled');
cy.get('.euiButton__text').contains('Delete').trigger('mouseover').click();
cy.get('.euiTextAlign').contains('No Queries or Visualizations').should('exist');
Expand All @@ -445,8 +488,8 @@ describe('clean up all test data', () => {
cy.get('.euiButton__text').contains('Actions').trigger('mouseover').click();
cy.get('.euiContextMenuItem__text').contains('Delete').trigger('mouseover').click();
cy.get('button.euiButton--danger').should('be.disabled');
cy.get('input.euiFieldText[placeholder="delete"]').focus().type('delete', { delay: 50, });
cy.get('input.euiFieldText[placeholder="delete"]').focus().type('delete', { delay: 50 });
cy.get('button.euiButton--danger').should('not.be.disabled');
cy.get('.euiButton__text').contains('Delete').trigger('mouseover').click();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`<ParaOutput /> spec renders markdown outputs 1`] = `
<div
class="euiText euiText--medium markdown-output-text"
class="euiText euiText--medium wrapAll markdown-output-text"
>
<div
class="markdown-body "
Expand All @@ -27,7 +27,7 @@ exports[`<ParaOutput /> spec renders other types of outputs 1`] = `
exports[`<ParaOutput /> spec renders query outputs 1`] = `
<div>
<div
class="euiText euiText--medium"
class="euiText euiText--medium wrapAll"
>
<b>
select * from opensearch_dashboards_sample_data_flights limit 2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ exports[`<Paragraphs /> spec renders the component 1`] = `
style="opacity: 1; padding: 15px;"
>
<div
class="euiText euiText--medium markdown-output-text"
class="euiText euiText--medium wrapAll markdown-output-text"
>
<div
class="markdown-body "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import { EuiCodeBlock, EuiSpacer, EuiText } from '@elastic/eui';
import MarkdownRender from '@nteract/markdown';
import { Media } from '@nteract/outputs';
import moment from 'moment';
import React, { useState } from 'react';
import { VisualizationContainer } from '../../../../components/custom_panels/panel_modules/visualization_container';
import PPLService from '../../../../services/requests/ppl';
import React, { useState } from 'react';
import { CoreStart } from '../../../../../../../src/core/public';
import {
DashboardContainerInput,
Expand Down Expand Up @@ -38,7 +38,7 @@ export const ParaOutput = (props: {
}) => {
const createQueryColumns = (jsonColumns: any[]) => {
let index = 0;
let datagridColumns = [];
const datagridColumns = [];
for (index = 0; index < jsonColumns.length; ++index) {
const datagridColumnObject = {
id: jsonColumns[index].name,
Expand All @@ -54,7 +54,7 @@ export const ParaOutput = (props: {
let index = 0;
let schemaIndex = 0;
for (index = 0; index < queryObject.datarows.length; ++index) {
let datarowValue = {};
const datarowValue = {};
for (schemaIndex = 0; schemaIndex < queryObject.schema.length; ++schemaIndex) {
const columnName = queryObject.schema[schemaIndex].name;
if (typeof queryObject.datarows[index][schemaIndex] === 'object') {
Expand All @@ -70,7 +70,34 @@ export const ParaOutput = (props: {
return data;
};

const outputBody = (key: string, typeOut: string, val: string) => {
const QueryOutput = ({ typeOut, val }: { typeOut: string; val: string }) => {
const inputQuery = para.inp.substring(4, para.inp.length);
const queryObject = JSON.parse(val);
const columns = createQueryColumns(queryObject.schema);
const data = getQueryOutputData(queryObject);
const [visibleColumns, setVisibleColumns] = useState(() => columns.map(({ id }) => id));
if (queryObject.hasOwnProperty('error')) {
return <EuiCodeBlock>{val}</EuiCodeBlock>;
} else {
return (
<div>
<EuiText className="wrapAll">
<b>{inputQuery}</b>
</EuiText>
<EuiSpacer />
<QueryDataGridMemo
rowCount={queryObject.datarows.length}
queryColumns={columns}
visibleColumns={visibleColumns}
setVisibleColumns={setVisibleColumns}
dataValues={data}
/>
</div>
);
}
};

const OutputBody = ({ typeOut, val }: { typeOut: string; val: string }) => {
/* Returns a component to render paragraph outputs using the para.typeOut property
* Currently supports HTML, TABLE, IMG
* TODO: add table rendering
Expand All @@ -80,34 +107,10 @@ export const ParaOutput = (props: {
if (typeOut !== undefined) {
switch (typeOut) {
case 'QUERY':
const inputQuery = para.inp.substring(4, para.inp.length);
const queryObject = JSON.parse(val);
if (queryObject.hasOwnProperty('error')) {
return <EuiCodeBlock key={key}>{val}</EuiCodeBlock>;
} else {
const columns = createQueryColumns(queryObject.schema);
const data = getQueryOutputData(queryObject);
const [visibleColumns, setVisibleColumns] = useState(() => columns.map(({ id }) => id));
return (
<div>
<EuiText key={'query-input-key'}>
<b>{inputQuery}</b>
</EuiText>
<EuiSpacer />
<QueryDataGridMemo
key={key}
rowCount={queryObject.datarows.length}
queryColumns={columns}
visibleColumns={visibleColumns}
setVisibleColumns={setVisibleColumns}
dataValues={data}
/>
</div>
);
}
return <QueryOutput typeOut={typeOut} val={val} />;
case 'MARKDOWN':
return (
<EuiText key={key} className="markdown-output-text">
<EuiText className="wrapAll markdown-output-text">
<MarkdownRender source={val} />
</EuiText>
);
Expand All @@ -121,11 +124,7 @@ export const ParaOutput = (props: {
<EuiText size="s" style={{ marginLeft: 9 }}>
{`${from} - ${to}`}
</EuiText>
<DashboardContainerByValueRenderer
key={key}
input={visInput}
onInputUpdated={setVisInput}
/>
<DashboardContainerByValueRenderer input={visInput} onInputUpdated={setVisInput} />
</>
);
case 'OBSERVABILITY_VISUALIZATION':
Expand Down Expand Up @@ -160,17 +159,17 @@ export const ParaOutput = (props: {
);
case 'HTML':
return (
<EuiText key={key}>
<EuiText>
{/* eslint-disable-next-line react/jsx-pascal-case */}
<Media.HTML data={val} />
</EuiText>
);
case 'TABLE':
return <pre key={key}>{val}</pre>;
return <pre>{val}</pre>;
case 'IMG':
return <img alt="" src={'data:image/gif;base64,' + val} key={key} />;
return <img alt="" src={'data:image/gif;base64,' + val} />;
default:
return <pre key={key}>{val}</pre>;
return <pre>{val}</pre>;
}
} else {
console.log('output not supported', typeOut);
Expand All @@ -183,7 +182,13 @@ export const ParaOutput = (props: {
return !para.isOutputHidden ? (
<>
{para.typeOut.map((typeOut: string, tIdx: number) => {
return outputBody(para.uniqueId + '_paraOutputBody', typeOut, para.out[tIdx]);
return (
<OutputBody
key={para.uniqueId + '_paraOutputBody_' + tIdx}
typeOut={typeOut}
val={para.out[tIdx]}
/>
);
})}
</>
) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => {
<ParaOutput
http={http}
pplService={pplService}
key={para.uniqueId}
para={para}
visInput={visInput}
setVisInput={setVisInput}
Expand Down
5 changes: 5 additions & 0 deletions public/components/notebooks/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
font-weight: normal;
}

.wrapAll {
word-break: break-all;
word-wrap: break-word;
}

.markdown-output-text {
font-family: 'Inter UI', -apple-system, system-ui, 'Segoe UI', Helvetica, Arial, sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
Expand Down