Skip to content
This repository has been archived by the owner on Oct 7, 2022. It is now read-only.

Add sample notebooks #50

Merged
merged 5 commits into from
Jul 7, 2021
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
4 changes: 2 additions & 2 deletions dashboards-notebooks/.cypress/integration/ui.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,13 +286,13 @@ describe('Testing paragraphs', () => {
cy.wait(delay);
cy.get('.euiContextMenuItem__text').contains('Add paragraph to top').click();
cy.wait(delay);
cy.get('.euiContextMenuItem__text').contains('Markdown').click();
cy.get('.euiContextMenuItem__text').contains('Code block').click();
cy.wait(delay);
cy.get('.euiButton__text').contains('Paragraph actions').click();
cy.wait(delay);
cy.get('.euiContextMenuItem__text').contains('Add paragraph to bottom').click();
cy.wait(delay);
cy.get('.euiContextMenuItem__text').contains('Markdown').click();
cy.get('.euiContextMenuItem__text').contains('Code block').click();
cy.wait(delay);

cy.get('.euiText').contains('[4] OpenSearch Dashboards visualization').should('exist');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,28 @@ export const getCloneModal = (
);
};

export const getSampleNotebooksModal = (
onCancel: (
event?: React.KeyboardEvent<HTMLDivElement> | React.MouseEvent<HTMLButtonElement, MouseEvent>
) => void,
onConfirm: (event?: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void
) => {
return (
<EuiOverlayMask>
<EuiConfirmModal
title="Add sample notebooks"
onCancel={onCancel}
onConfirm={onConfirm}
cancelButtonText="Cancel"
confirmButtonText="Yes"
defaultFocusedButton="confirm"
>
<p>Do you want to add sample notebooks? This will also add Dashboards sample flights and logs data if they have not been added.</p>
</EuiConfirmModal>
</EuiOverlayMask>
);
};

export const getDeleteModal = (
onCancel: (
event?: React.KeyboardEvent<HTMLDivElement> | React.MouseEvent<HTMLButtonElement, MouseEvent>
Expand Down
91 changes: 82 additions & 9 deletions dashboards-notebooks/public/components/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,18 @@
* permissions and limitations under the License.
*/

import { EuiGlobalToastList, EuiLink } from '@elastic/eui';
import { Toast } from '@elastic/eui/src/components/toast/global_toast_list';
import React, { ReactChild } from 'react';

import { CoreStart, ChromeBreadcrumb } from '../../../../src/core/public';
import { Route, Switch } from 'react-router';
import { HashRouter } from 'react-router-dom';
import { ChromeBreadcrumb, CoreStart } from '../../../../src/core/public';
import { DashboardStart } from '../../../../src/plugins/dashboard/public';

import { Notebook } from './notebook';
import { API_PREFIX, DOCUMENTATION_URL } from '../../common';
import { Notebook } from './notebook';
import { NoteTable } from './note_table';
import { HashRouter } from 'react-router-dom';
import { Switch, Route } from 'react-router';
import { EuiGlobalToastList, EuiLink } from '@elastic/eui';
import { Toast } from '@elastic/eui/src/components/toast/global_toast_list';
import { useHistory } from "react-router-dom";



/*
* "Main" component renders the whole Notebooks as a single page application
Expand All @@ -60,6 +59,7 @@ type MainState = {
data: Array<NotebookType>;
openedNotebook: NotebookType | undefined;
toasts: Toast[];
loading: boolean;
};

export type NotebookType = {
Expand All @@ -76,6 +76,7 @@ export class Main extends React.Component<MainProps, MainState> {
data: [],
openedNotebook: undefined,
toasts: [],
loading: false,
};
}

Expand Down Expand Up @@ -207,6 +208,76 @@ export class Main extends React.Component<MainProps, MainState> {
console.error(err.body.message);
});
};

addSampleNotebooks = async () => {
try {
this.setState({ loading: true });
const flights = await this.props.http
.get('../api/saved_objects/_find', {
query: {
type: 'index-pattern',
search_fields: 'title',
search: 'opensearch_dashboards_sample_data_flights',
}
})
.then((resp) => resp.total === 0);
const logs = await this.props.http
.get('../api/saved_objects/_find', {
query: {
type: 'index-pattern',
search_fields: 'title',
search: 'opensearch_dashboards_sample_data_logs',
}
})
.then((resp) => resp.total === 0);
if (flights || logs)
this.setToast('Adding sample data. This can take some time.');
await Promise.all([
flights ? this.props.http.post('../api/sample_data/flights') : Promise.resolve(),
logs ? this.props.http.post('../api/sample_data/logs') : Promise.resolve()
]);
const visIds: string[] = [];
await this.props.http
.get('../api/saved_objects/_find', {
query: {
type: 'visualization',
search_fields: 'title',
search: '[Logs] Response Codes Over Time + Annotations',
}
})
.then((resp) => visIds.push(resp.saved_objects[0].id));
await this.props.http
.get('../api/saved_objects/_find', {
query: {
type: 'visualization',
search_fields: 'title',
search: '[Logs] Unique Visitors vs. Average Bytes',
}
})
.then((resp) => visIds.push(resp.saved_objects[0].id));
await this.props.http
.post(`${API_PREFIX}/note/addSampleNotebooks`, {
body: JSON.stringify({ visIds }),
})
.then((res) => {
const newData = res.body.map((notebook) => ({
path: notebook.name,
id: notebook.id,
dateCreated: notebook.dateCreated,
dateModified: notebook.dateModified,
}))
this.setState((prevState) => ({
data: [...prevState.data, ...newData],
}));
});
this.setToast(`Sample notebooks successfully added.`);
} catch (err) {
this.setToast('Error adding sample notebooks.', 'danger');
console.error(err.body.message);
} finally {
this.setState({ loading: false });
}
};

render() {
return (
Expand Down Expand Up @@ -242,7 +313,9 @@ export class Main extends React.Component<MainProps, MainState> {
path='/'
render={(props) =>
<NoteTable
loading={this.state.loading}
fetchNotebooks={this.fetchNotebooks}
addSampleNotebooks={this.addSampleNotebooks}
notebooks={this.state.data}
createNotebook={this.createNotebook}
renameNotebook={this.renameNotebook}
Expand Down
28 changes: 26 additions & 2 deletions dashboards-notebooks/public/components/note_table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ import moment from 'moment';
import React, { useEffect, useState, ReactElement } from 'react';
import { ChromeBreadcrumb } from '../../../../src/core/public';
import { CREATE_NOTE_MESSAGE, DATE_FORMAT, DOCUMENTATION_URL } from '../../common';
import { getCustomModal, DeleteNotebookModal } from './helpers/modal_containers';
import { getCustomModal, DeleteNotebookModal, getSampleNotebooksModal } from './helpers/modal_containers';
import { NotebookType } from './main';

const pageStyles: CSS.Properties = {
Expand All @@ -63,7 +63,9 @@ const pageStyles: CSS.Properties = {
}

type NoteTableProps = {
loading: boolean;
fetchNotebooks: () => void;
addSampleNotebooks: () => void;
notebooks: Array<NotebookType>;
createNotebook: (newNoteName: string) => void;
renameNotebook: (newNoteName: string, noteId: string) => void;
Expand Down Expand Up @@ -191,6 +193,14 @@ export function NoteTable(props: NoteTableProps) {
);
showModal();
};

const addSampleNotebooks = async () => {
setModalLayout(getSampleNotebooksModal(closeModal, async () => {
closeModal();
await props.addSampleNotebooks();
}));
showModal();
}

const popoverButton = (
<EuiButton iconType="arrowDown" iconSide="right" onClick={() => setIsActionsPopoverOpen(!isActionsPopoverOpen)}>
Expand Down Expand Up @@ -226,6 +236,14 @@ export function NoteTable(props: NoteTableProps) {
}}>
Delete
</EuiContextMenuItem>,
<EuiContextMenuItem
key="addSample"
onClick={() => {
setIsActionsPopoverOpen(false);
addSampleNotebooks();
}}>
Add sample notebooks
</EuiContextMenuItem>,
];

const tableColumns = [
Expand Down Expand Up @@ -301,6 +319,7 @@ export function NoteTable(props: NoteTableProps) {
<EuiHorizontalRule margin='m' />
{notebooks.length > 0 ? (
<EuiInMemoryTable
loading={props.loading}
items={searchQuery ?
notebooks.filter((notebook) => notebook.path.toLowerCase().includes(searchQuery.toLowerCase())) :
notebooks}
Expand Down Expand Up @@ -335,12 +354,17 @@ export function NoteTable(props: NoteTableProps) {
</EuiText>
</EuiText>
<EuiSpacer size='m' />
<EuiFlexGroup justifyContent='spaceAround'>
<EuiFlexGroup justifyContent='center'>
<EuiFlexItem grow={false}>
<EuiButton fullWidth={false} onClick={() => createNote()}>
Create notebook
</EuiButton>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton fullWidth={false} onClick={() => addSampleNotebooks()}>
Add sample notebooks
</EuiButton>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size='xxl' />
</>
Expand Down
8 changes: 4 additions & 4 deletions dashboards-notebooks/public/components/notebook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -750,14 +750,14 @@ export class Notebook extends Component<NotebookProps, NotebookState> {
title: 'Add to top',
items: [
{
name: 'Markdown',
name: 'Code block',
onClick: () => {
this.setState({ isParaActionsPopoverOpen: false });
this.addPara(0, '', 'CODE');
},
},
{
name: 'OpenSearch Dashboards visualization',
name: 'Visualization',
onClick: () => {
this.setState({ isParaActionsPopoverOpen: false });
this.addPara(0, '', 'VISUALIZATION');
Expand All @@ -770,14 +770,14 @@ export class Notebook extends Component<NotebookProps, NotebookState> {
title: 'Add to bottom',
items: [
{
name: 'Markdown',
name: 'Code block',
onClick: () => {
this.setState({ isParaActionsPopoverOpen: false });
this.addPara(this.state.paragraphs.length, '', 'CODE');
},
},
{
name: 'OpenSearch Dashboards visualization',
name: 'Visualization',
onClick: () => {
this.setState({ isParaActionsPopoverOpen: false });
this.addPara(this.state.paragraphs.length, '', 'VISUALIZATION');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => {
title: 'Insert paragraph above',
items: [
{
name: 'Markdown',
name: 'Code block',
onClick: () => {
setIsPopoverOpen(false);
props.addPara(index, '', 'CODE');
Expand All @@ -341,7 +341,7 @@ export const Paragraphs = forwardRef((props: ParagraphProps, ref) => {
title: 'Insert paragraph below',
items: [
{
name: 'Markdown',
name: 'Code block',
onClick: () => {
setIsPopoverOpen(false);
props.addPara(index + 1, '', 'CODE');
Expand Down
29 changes: 29 additions & 0 deletions dashboards-notebooks/server/adaptors/default_backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
} from '../helpers/default_notebook_schema';
import { formatNotRecognized, inputIsQuery } from '../helpers/query_helpers';
import now from "performance-now";
import { getSampleNotebooks } from '../helpers/sample_notebooks';

export class DefaultBackend implements NotebookAdaptor {
backend = 'Default Backend';
Expand Down Expand Up @@ -158,6 +159,34 @@ export class DefaultBackend implements NotebookAdaptor {
}
};

/* Adds sample notebooks to storage
* Param: name -> name of new notebook
*/
addSampleNotes = async function (
client: ILegacyScopedClusterClient,
visIds: string[],
_wreckOptions: optionsType
) {
try {
const notebooks = getSampleNotebooks(visIds);
const newNotebooks: any[] = [];
for (let i = 0; i < notebooks.length; i++) {
const notebook = notebooks[i];
await this.indexNote(client, notebook.notebook).then((response) => {
newNotebooks.push({
id: response.notebookId,
name: notebook.notebook.name,
dateModified: notebook.dateModified,
dateCreated: notebook.dateCreated,
});
});
}
return { status: 'OK', message: '', body: newNotebooks };
} catch (error) {
throw new Error('Creating New Notebook Error:' + error);
}
};

/* Renames a notebook
* Params: name -> new name for the notebook to be renamed
* noteId -> Id of notebook to be fetched
Expand Down
Loading