[Canvas][tech-debt] Add Typescript to apps directory (#73766)
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
7dc33f9ba8
commit
c6c300e8f8
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { mount } from 'enzyme';
|
import { mount } from 'enzyme';
|
||||||
// @ts-expect-error untyped local
|
import { ExportApp } from '../export_app.component';
|
||||||
import { ExportApp } from '../export_app';
|
import { CanvasWorkpad } from '../../../../../types';
|
||||||
|
|
||||||
jest.mock('style-it', () => ({
|
jest.mock('style-it', () => ({
|
||||||
it: (css: string, Component: any) => Component,
|
it: (css: string, Component: any) => Component,
|
||||||
|
@ -23,7 +23,7 @@ jest.mock('../../../../components/link', () => ({
|
||||||
|
|
||||||
describe('<ExportApp />', () => {
|
describe('<ExportApp />', () => {
|
||||||
test('renders as expected', () => {
|
test('renders as expected', () => {
|
||||||
const sampleWorkpad = {
|
const sampleWorkpad = ({
|
||||||
id: 'my-workpad-abcd',
|
id: 'my-workpad-abcd',
|
||||||
css: '',
|
css: '',
|
||||||
pages: [
|
pages: [
|
||||||
|
@ -34,7 +34,7 @@ describe('<ExportApp />', () => {
|
||||||
elements: [3, 4, 5, 6],
|
elements: [3, 4, 5, 6],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
} as any) as CanvasWorkpad;
|
||||||
|
|
||||||
const page1 = mount(
|
const page1 = mount(
|
||||||
<ExportApp workpad={sampleWorkpad} selectedPageIndex={0} initializeWorkpad={() => {}} />
|
<ExportApp workpad={sampleWorkpad} selectedPageIndex={0} initializeWorkpad={() => {}} />
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { FC, useEffect } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
// @ts-expect-error untyped library
|
||||||
|
import Style from 'style-it';
|
||||||
|
// @ts-expect-error untyped local
|
||||||
|
import { WorkpadPage } from '../../../components/workpad_page';
|
||||||
|
import { Link } from '../../../components/link';
|
||||||
|
import { CanvasWorkpad } from '../../../../types';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
workpad: CanvasWorkpad;
|
||||||
|
selectedPageIndex: number;
|
||||||
|
initializeWorkpad: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ExportApp: FC<Props> = ({ workpad, selectedPageIndex, initializeWorkpad }) => {
|
||||||
|
const { id, pages, height, width } = workpad;
|
||||||
|
const activePage = pages[selectedPageIndex];
|
||||||
|
const pageElementCount = activePage.elements.length;
|
||||||
|
|
||||||
|
useEffect(() => initializeWorkpad());
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="canvasExport" data-shared-page={selectedPageIndex + 1}>
|
||||||
|
<div className="canvasExport__stage">
|
||||||
|
<div className="canvasLayout__stageHeader">
|
||||||
|
<Link name="loadWorkpad" params={{ id }}>
|
||||||
|
Edit Workpad
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
{Style.it(
|
||||||
|
workpad.css,
|
||||||
|
<div className="canvasExport__stageContent" data-shared-items-count={pageElementCount}>
|
||||||
|
<WorkpadPage
|
||||||
|
isSelected
|
||||||
|
key={activePage.id}
|
||||||
|
pageId={activePage.id}
|
||||||
|
height={height}
|
||||||
|
width={width}
|
||||||
|
registerLayout={() => {}}
|
||||||
|
unregisterLayout={() => {}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ExportApp.propTypes = {
|
||||||
|
workpad: PropTypes.shape({
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
pages: PropTypes.array.isRequired,
|
||||||
|
}).isRequired,
|
||||||
|
selectedPageIndex: PropTypes.number.isRequired,
|
||||||
|
initializeWorkpad: PropTypes.func.isRequired,
|
||||||
|
};
|
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Style from 'style-it';
|
|
||||||
import { WorkpadPage } from '../../../components/workpad_page';
|
|
||||||
import { Link } from '../../../components/link';
|
|
||||||
|
|
||||||
export class ExportApp extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
workpad: PropTypes.shape({
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
pages: PropTypes.array.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
selectedPageIndex: PropTypes.number.isRequired,
|
|
||||||
initializeWorkpad: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.props.initializeWorkpad();
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { workpad, selectedPageIndex } = this.props;
|
|
||||||
const { pages, height, width } = workpad;
|
|
||||||
const activePage = pages[selectedPageIndex];
|
|
||||||
const pageElementCount = activePage.elements.length;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="canvasExport" data-shared-page={selectedPageIndex + 1}>
|
|
||||||
<div className="canvasExport__stage">
|
|
||||||
<div className="canvasLayout__stageHeader">
|
|
||||||
<Link name="loadWorkpad" params={{ id: this.props.workpad.id }}>
|
|
||||||
Edit Workpad
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
{Style.it(
|
|
||||||
workpad.css,
|
|
||||||
<div className="canvasExport__stageContent" data-shared-items-count={pageElementCount}>
|
|
||||||
<WorkpadPage
|
|
||||||
isSelected
|
|
||||||
key={activePage.id}
|
|
||||||
pageId={activePage.id}
|
|
||||||
height={height}
|
|
||||||
width={width}
|
|
||||||
registerLayout={() => {}}
|
|
||||||
unregisterLayout={() => {}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { initializeWorkpad } from '../../../state/actions/workpad';
|
||||||
|
import { getWorkpad, getSelectedPageIndex } from '../../../state/selectors/workpad';
|
||||||
|
import { ExportApp as Component } from './export_app.component';
|
||||||
|
import { State } from '../../../../types';
|
||||||
|
|
||||||
|
export const ExportApp = connect(
|
||||||
|
(state: State) => ({
|
||||||
|
workpad: getWorkpad(state),
|
||||||
|
selectedPageIndex: getSelectedPageIndex(state),
|
||||||
|
}),
|
||||||
|
(dispatch) => ({
|
||||||
|
initializeWorkpad: () => dispatch(initializeWorkpad()),
|
||||||
|
})
|
||||||
|
)(Component);
|
|
@ -1,30 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { compose, branch, renderComponent } from 'recompose';
|
|
||||||
import { initializeWorkpad } from '../../../state/actions/workpad';
|
|
||||||
import { getWorkpad, getSelectedPageIndex } from '../../../state/selectors/workpad';
|
|
||||||
import { LoadWorkpad } from './load_workpad';
|
|
||||||
import { ExportApp as Component } from './export_app';
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
|
||||||
workpad: getWorkpad(state),
|
|
||||||
selectedPageIndex: getSelectedPageIndex(state),
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
initializeWorkpad() {
|
|
||||||
dispatch(initializeWorkpad());
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const branches = [branch(({ workpad }) => workpad == null, renderComponent(LoadWorkpad))];
|
|
||||||
|
|
||||||
export const ExportApp = compose(
|
|
||||||
connect(mapStateToProps, mapDispatchToProps),
|
|
||||||
...branches
|
|
||||||
)(Component);
|
|
|
@ -4,6 +4,5 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
export { ExportApp } from './export_app';
|
||||||
|
export { ExportApp as ExportAppComponent } from './export_app.component';
|
||||||
export const LoadWorkpad = () => <div>Load a workpad...</div>;
|
|
|
@ -4,10 +4,15 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
// @ts-expect-error Untyped local
|
||||||
import * as workpadService from '../../lib/workpad_service';
|
import * as workpadService from '../../lib/workpad_service';
|
||||||
import { setWorkpad } from '../../state/actions/workpad';
|
import { setWorkpad } from '../../state/actions/workpad';
|
||||||
|
// @ts-expect-error Untyped local
|
||||||
import { fetchAllRenderables } from '../../state/actions/elements';
|
import { fetchAllRenderables } from '../../state/actions/elements';
|
||||||
|
// @ts-expect-error Untyped local
|
||||||
import { setPage } from '../../state/actions/pages';
|
import { setPage } from '../../state/actions/pages';
|
||||||
|
// @ts-expect-error Untyped local
|
||||||
import { setAssets } from '../../state/actions/assets';
|
import { setAssets } from '../../state/actions/assets';
|
||||||
import { ExportApp } from './export';
|
import { ExportApp } from './export';
|
||||||
|
|
||||||
|
@ -18,7 +23,13 @@ export const routes = [
|
||||||
{
|
{
|
||||||
name: 'exportWorkpad',
|
name: 'exportWorkpad',
|
||||||
path: '/pdf/:id/page/:page',
|
path: '/pdf/:id/page/:page',
|
||||||
action: (dispatch) => async ({ params, router }) => {
|
action: (dispatch: Dispatch) => async ({
|
||||||
|
params,
|
||||||
|
// @ts-expect-error Fix when Router is typed.
|
||||||
|
router,
|
||||||
|
}: {
|
||||||
|
params: { id: string; page: string };
|
||||||
|
}) => {
|
||||||
// load workpad if given a new id via url param
|
// load workpad if given a new id via url param
|
||||||
const fetchedWorkpad = await workpadService.get(params.id);
|
const fetchedWorkpad = await workpadService.get(params.id);
|
||||||
const pageNumber = parseInt(params.page, 10);
|
const pageNumber = parseInt(params.page, 10);
|
|
@ -4,12 +4,18 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React, { FC } from 'react';
|
||||||
import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui';
|
import { EuiPage, EuiPageBody, EuiPageContent } from '@elastic/eui';
|
||||||
|
// @ts-expect-error untyped local
|
||||||
import { WorkpadManager } from '../../../components/workpad_manager';
|
import { WorkpadManager } from '../../../components/workpad_manager';
|
||||||
|
// @ts-expect-error untyped local
|
||||||
import { setDocTitle } from '../../../lib/doc_title';
|
import { setDocTitle } from '../../../lib/doc_title';
|
||||||
|
|
||||||
export const HomeApp = ({ onLoad = () => {} }) => {
|
interface Props {
|
||||||
|
onLoad: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const HomeApp: FC<Props> = ({ onLoad = () => {} }) => {
|
||||||
onLoad();
|
onLoad();
|
||||||
setDocTitle('Canvas');
|
setDocTitle('Canvas');
|
||||||
return (
|
return (
|
|
@ -6,12 +6,10 @@
|
||||||
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { resetWorkpad } from '../../../state/actions/workpad';
|
import { resetWorkpad } from '../../../state/actions/workpad';
|
||||||
import { HomeApp as Component } from './home_app';
|
import { HomeApp as Component } from './home_app.component';
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
export const HomeApp = connect(null, (dispatch) => ({
|
||||||
onLoad() {
|
onLoad() {
|
||||||
dispatch(resetWorkpad());
|
dispatch(resetWorkpad());
|
||||||
},
|
},
|
||||||
});
|
}))(Component);
|
||||||
|
|
||||||
export const HomeApp = connect(null, mapDispatchToProps)(Component);
|
|
|
@ -4,6 +4,5 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
export { HomeApp } from './home_app';
|
||||||
|
export { HomeApp as HomeAppComponent } from './home_app.component';
|
||||||
export const LoadWorkpad = () => <div>Load a workpad...</div>;
|
|
|
@ -8,6 +8,7 @@ import * as home from './home';
|
||||||
import * as workpad from './workpad';
|
import * as workpad from './workpad';
|
||||||
import * as exp from './export';
|
import * as exp from './export';
|
||||||
|
|
||||||
|
// @ts-expect-error Router and routes are not yet strongly typed
|
||||||
export const routes = [].concat(workpad.routes, home.routes, exp.routes);
|
export const routes = [].concat(workpad.routes, home.routes, exp.routes);
|
||||||
|
|
||||||
export const apps = [workpad.WorkpadApp, home.HomeApp, exp.ExportApp];
|
export const apps = [workpad.WorkpadApp, home.HomeApp, exp.ExportApp];
|
|
@ -4,17 +4,24 @@
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ErrorStrings } from '../../../i18n';
|
import { Dispatch } from 'redux';
|
||||||
|
// @ts-expect-error
|
||||||
import * as workpadService from '../../lib/workpad_service';
|
import * as workpadService from '../../lib/workpad_service';
|
||||||
import { notifyService } from '../../services';
|
import { notifyService } from '../../services';
|
||||||
import { getBaseBreadcrumb, getWorkpadBreadcrumb, setBreadcrumb } from '../../lib/breadcrumbs';
|
import { getBaseBreadcrumb, getWorkpadBreadcrumb, setBreadcrumb } from '../../lib/breadcrumbs';
|
||||||
|
// @ts-expect-error
|
||||||
import { getDefaultWorkpad } from '../../state/defaults';
|
import { getDefaultWorkpad } from '../../state/defaults';
|
||||||
import { setWorkpad } from '../../state/actions/workpad';
|
import { setWorkpad } from '../../state/actions/workpad';
|
||||||
|
// @ts-expect-error
|
||||||
import { setAssets, resetAssets } from '../../state/actions/assets';
|
import { setAssets, resetAssets } from '../../state/actions/assets';
|
||||||
|
// @ts-expect-error
|
||||||
import { setPage } from '../../state/actions/pages';
|
import { setPage } from '../../state/actions/pages';
|
||||||
import { getWorkpad } from '../../state/selectors/workpad';
|
import { getWorkpad } from '../../state/selectors/workpad';
|
||||||
|
// @ts-expect-error
|
||||||
import { setZoomScale } from '../../state/actions/transient';
|
import { setZoomScale } from '../../state/actions/transient';
|
||||||
|
import { ErrorStrings } from '../../../i18n';
|
||||||
import { WorkpadApp } from './workpad_app';
|
import { WorkpadApp } from './workpad_app';
|
||||||
|
import { State } from '../../../types';
|
||||||
|
|
||||||
const { workpadRoutes: strings } = ErrorStrings;
|
const { workpadRoutes: strings } = ErrorStrings;
|
||||||
|
|
||||||
|
@ -25,7 +32,8 @@ export const routes = [
|
||||||
{
|
{
|
||||||
name: 'createWorkpad',
|
name: 'createWorkpad',
|
||||||
path: '/create',
|
path: '/create',
|
||||||
action: (dispatch) => async ({ router }) => {
|
// @ts-expect-error Fix when Router is typed.
|
||||||
|
action: (dispatch: Dispatch) => async ({ router }) => {
|
||||||
const newWorkpad = getDefaultWorkpad();
|
const newWorkpad = getDefaultWorkpad();
|
||||||
try {
|
try {
|
||||||
await workpadService.create(newWorkpad);
|
await workpadService.create(newWorkpad);
|
||||||
|
@ -46,7 +54,13 @@ export const routes = [
|
||||||
{
|
{
|
||||||
name: 'loadWorkpad',
|
name: 'loadWorkpad',
|
||||||
path: '/:id(/page/:page)',
|
path: '/:id(/page/:page)',
|
||||||
action: (dispatch, getState) => async ({ params, router }) => {
|
action: (dispatch: Dispatch, getState: () => State) => async ({
|
||||||
|
params,
|
||||||
|
// @ts-expect-error Fix when Router is typed.
|
||||||
|
router,
|
||||||
|
}: {
|
||||||
|
params: { id: string; page?: string };
|
||||||
|
}) => {
|
||||||
// load workpad if given a new id via url param
|
// load workpad if given a new id via url param
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const currentWorkpad = getWorkpad(state);
|
const currentWorkpad = getWorkpad(state);
|
||||||
|
@ -70,10 +84,10 @@ export const routes = [
|
||||||
|
|
||||||
// fetch the workpad again, to get changes
|
// fetch the workpad again, to get changes
|
||||||
const workpad = getWorkpad(getState());
|
const workpad = getWorkpad(getState());
|
||||||
const pageNumber = parseInt(params.page, 10);
|
const pageNumber = params.page ? parseInt(params.page, 10) : null;
|
||||||
|
|
||||||
// no page provided, append current page to url
|
// no page provided, append current page to url
|
||||||
if (isNaN(pageNumber)) {
|
if (!pageNumber || isNaN(pageNumber)) {
|
||||||
return router.redirectTo('loadWorkpad', { id: workpad.id, page: workpad.page + 1 });
|
return router.redirectTo('loadWorkpad', { id: workpad.id, page: workpad.page + 1 });
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { compose, branch, renderComponent } from 'recompose';
|
|
||||||
import { selectToplevelNodes } from '../../../state/actions/transient';
|
|
||||||
import { canUserWrite, getAppReady } from '../../../state/selectors/app';
|
|
||||||
import { getWorkpad, isWriteable } from '../../../state/selectors/workpad';
|
|
||||||
import { LoadWorkpad } from './load_workpad';
|
|
||||||
import { WorkpadApp as Component } from './workpad_app';
|
|
||||||
import { withElementsLoadedTelemetry } from './workpad_telemetry';
|
|
||||||
|
|
||||||
export { WORKPAD_CONTAINER_ID } from './workpad_app';
|
|
||||||
|
|
||||||
const mapStateToProps = (state) => {
|
|
||||||
const appReady = getAppReady(state);
|
|
||||||
|
|
||||||
return {
|
|
||||||
isWriteable: isWriteable(state) && canUserWrite(state),
|
|
||||||
appReady: typeof appReady === 'object' ? appReady : { ready: appReady },
|
|
||||||
workpad: getWorkpad(state),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
deselectElement(ev) {
|
|
||||||
ev && ev.stopPropagation();
|
|
||||||
dispatch(selectToplevelNodes([]));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const branches = [branch(({ workpad }) => workpad == null, renderComponent(LoadWorkpad))];
|
|
||||||
|
|
||||||
export const WorkpadApp = compose(
|
|
||||||
connect(mapStateToProps, mapDispatchToProps),
|
|
||||||
...branches,
|
|
||||||
withElementsLoadedTelemetry
|
|
||||||
)(Component);
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export { WorkpadApp } from './workpad_app';
|
||||||
|
export { WorkpadApp as WorkpadAppComponent } from './workpad_app.component';
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { FC, MouseEventHandler, useRef } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Sidebar } from '../../../components/sidebar';
|
||||||
|
import { Toolbar } from '../../../components/toolbar';
|
||||||
|
// @ts-expect-error Untyped local
|
||||||
|
import { Workpad } from '../../../components/workpad';
|
||||||
|
import { WorkpadHeader } from '../../../components/workpad_header';
|
||||||
|
import { CANVAS_LAYOUT_STAGE_CONTENT_SELECTOR } from '../../../../common/lib/constants';
|
||||||
|
import { CommitFn } from '../../../../types';
|
||||||
|
|
||||||
|
export const WORKPAD_CONTAINER_ID = 'canvasWorkpadContainer';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
deselectElement?: MouseEventHandler;
|
||||||
|
isWriteable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WorkpadApp: FC<Props> = ({ deselectElement, isWriteable }) => {
|
||||||
|
const interactivePageLayout = useRef<CommitFn | null>(null); // future versions may enable editing on multiple pages => use array then
|
||||||
|
|
||||||
|
const registerLayout = (newLayout: CommitFn) => {
|
||||||
|
if (interactivePageLayout.current !== newLayout) {
|
||||||
|
interactivePageLayout.current = newLayout;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const unregisterLayout = (oldLayout: CommitFn) => {
|
||||||
|
if (interactivePageLayout.current === oldLayout) {
|
||||||
|
interactivePageLayout.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const commit = interactivePageLayout.current || (() => {});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="canvasLayout">
|
||||||
|
<div className="canvasLayout__rows">
|
||||||
|
<div className="canvasLayout__cols">
|
||||||
|
<div className="canvasLayout__stage">
|
||||||
|
<div className="canvasLayout__stageHeader">
|
||||||
|
<WorkpadHeader commit={commit} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
id={CANVAS_LAYOUT_STAGE_CONTENT_SELECTOR}
|
||||||
|
className={CANVAS_LAYOUT_STAGE_CONTENT_SELECTOR}
|
||||||
|
onMouseDown={deselectElement}
|
||||||
|
>
|
||||||
|
{/* NOTE: canvasWorkpadContainer is used for exporting */}
|
||||||
|
<div
|
||||||
|
id={WORKPAD_CONTAINER_ID}
|
||||||
|
className="canvasWorkpadContainer canvasLayout__stageContentOverflow"
|
||||||
|
>
|
||||||
|
<Workpad registerLayout={registerLayout} unregisterLayout={unregisterLayout} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{isWriteable && (
|
||||||
|
<div className="canvasLayout__sidebar hide-for-sharing">
|
||||||
|
<Sidebar commit={commit} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="canvasLayout__footer hide-for-sharing">
|
||||||
|
<Toolbar />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
WorkpadApp.propTypes = {
|
||||||
|
isWriteable: PropTypes.bool.isRequired,
|
||||||
|
deselectElement: PropTypes.func,
|
||||||
|
};
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
|
||||||
* you may not use this file except in compliance with the Elastic License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { Sidebar } from '../../../components/sidebar';
|
|
||||||
import { Toolbar } from '../../../components/toolbar';
|
|
||||||
import { Workpad } from '../../../components/workpad';
|
|
||||||
import { WorkpadHeader } from '../../../components/workpad_header';
|
|
||||||
import { CANVAS_LAYOUT_STAGE_CONTENT_SELECTOR } from '../../../../common/lib/constants';
|
|
||||||
|
|
||||||
export const WORKPAD_CONTAINER_ID = 'canvasWorkpadContainer';
|
|
||||||
|
|
||||||
export class WorkpadApp extends React.PureComponent {
|
|
||||||
static propTypes = {
|
|
||||||
isWriteable: PropTypes.bool.isRequired,
|
|
||||||
deselectElement: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
interactivePageLayout = null; // future versions may enable editing on multiple pages => use array then
|
|
||||||
|
|
||||||
registerLayout(newLayout) {
|
|
||||||
if (this.interactivePageLayout !== newLayout) {
|
|
||||||
this.interactivePageLayout = newLayout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unregisterLayout(oldLayout) {
|
|
||||||
if (this.interactivePageLayout === oldLayout) {
|
|
||||||
this.interactivePageLayout = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { isWriteable, deselectElement } = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="canvasLayout">
|
|
||||||
<div className="canvasLayout__rows">
|
|
||||||
<div className="canvasLayout__cols">
|
|
||||||
<div className="canvasLayout__stage">
|
|
||||||
<div className="canvasLayout__stageHeader">
|
|
||||||
<WorkpadHeader commit={this.interactivePageLayout || (() => {})} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
id={CANVAS_LAYOUT_STAGE_CONTENT_SELECTOR}
|
|
||||||
className={CANVAS_LAYOUT_STAGE_CONTENT_SELECTOR}
|
|
||||||
onMouseDown={deselectElement}
|
|
||||||
>
|
|
||||||
{/* NOTE: canvasWorkpadContainer is used for exporting */}
|
|
||||||
<div
|
|
||||||
id={WORKPAD_CONTAINER_ID}
|
|
||||||
className="canvasWorkpadContainer canvasLayout__stageContentOverflow"
|
|
||||||
>
|
|
||||||
<Workpad
|
|
||||||
registerLayout={this.registerLayout.bind(this)}
|
|
||||||
unregisterLayout={this.unregisterLayout.bind(this)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{isWriteable && (
|
|
||||||
<div className="canvasLayout__sidebar hide-for-sharing">
|
|
||||||
<Sidebar />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="canvasLayout__footer hide-for-sharing">
|
|
||||||
<Toolbar />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
import { MouseEventHandler } from 'react';
|
||||||
|
import { Dispatch } from 'redux';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
// @ts-expect-error untyped local
|
||||||
|
import { selectToplevelNodes } from '../../../state/actions/transient';
|
||||||
|
import { canUserWrite } from '../../../state/selectors/app';
|
||||||
|
import { getWorkpad, isWriteable } from '../../../state/selectors/workpad';
|
||||||
|
import { WorkpadApp as Component } from './workpad_app.component';
|
||||||
|
import { withElementsLoadedTelemetry } from './workpad_telemetry';
|
||||||
|
import { State } from '../../../../types';
|
||||||
|
|
||||||
|
export { WORKPAD_CONTAINER_ID } from './workpad_app.component';
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch: Dispatch): { deselectElement: MouseEventHandler } => ({
|
||||||
|
deselectElement: (ev) => {
|
||||||
|
ev.stopPropagation();
|
||||||
|
dispatch(selectToplevelNodes([]));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WorkpadApp = connect(
|
||||||
|
(state: State) => ({
|
||||||
|
isWriteable: isWriteable(state) && canUserWrite(state),
|
||||||
|
workpad: getWorkpad(state),
|
||||||
|
}),
|
||||||
|
mapDispatchToProps
|
||||||
|
)(withElementsLoadedTelemetry(Component));
|
|
@ -18,22 +18,25 @@ import { EditMenu } from './edit_menu';
|
||||||
import { ElementMenu } from './element_menu';
|
import { ElementMenu } from './element_menu';
|
||||||
import { ShareMenu } from './share_menu';
|
import { ShareMenu } from './share_menu';
|
||||||
import { ViewMenu } from './view_menu';
|
import { ViewMenu } from './view_menu';
|
||||||
|
import { CommitFn } from '../../../types';
|
||||||
|
|
||||||
const { WorkpadHeader: strings } = ComponentStrings;
|
const { WorkpadHeader: strings } = ComponentStrings;
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
isWriteable: boolean;
|
isWriteable: boolean;
|
||||||
toggleWriteable: () => void;
|
|
||||||
canUserWrite: boolean;
|
canUserWrite: boolean;
|
||||||
commit: (type: string, payload: any) => any;
|
commit: CommitFn;
|
||||||
|
onSetWriteable?: (writeable: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WorkpadHeader: FunctionComponent<Props> = ({
|
export const WorkpadHeader: FunctionComponent<Props> = ({
|
||||||
isWriteable,
|
isWriteable,
|
||||||
canUserWrite,
|
canUserWrite,
|
||||||
toggleWriteable,
|
|
||||||
commit,
|
commit,
|
||||||
|
onSetWriteable = () => {},
|
||||||
}) => {
|
}) => {
|
||||||
|
const toggleWriteable = () => onSetWriteable(!isWriteable);
|
||||||
|
|
||||||
const keyHandler = (action: string) => {
|
const keyHandler = (action: string) => {
|
||||||
if (action === 'EDITING') {
|
if (action === 'EDITING') {
|
||||||
toggleWriteable();
|
toggleWriteable();
|
||||||
|
@ -145,6 +148,7 @@ export const WorkpadHeader: FunctionComponent<Props> = ({
|
||||||
|
|
||||||
WorkpadHeader.propTypes = {
|
WorkpadHeader.propTypes = {
|
||||||
isWriteable: PropTypes.bool,
|
isWriteable: PropTypes.bool,
|
||||||
toggleWriteable: PropTypes.func,
|
commit: PropTypes.func.isRequired,
|
||||||
|
onSetWriteable: PropTypes.func,
|
||||||
canUserWrite: PropTypes.bool,
|
canUserWrite: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,37 +10,16 @@ import { canUserWrite } from '../../state/selectors/app';
|
||||||
import { getSelectedPage, isWriteable } from '../../state/selectors/workpad';
|
import { getSelectedPage, isWriteable } from '../../state/selectors/workpad';
|
||||||
import { setWriteable } from '../../state/actions/workpad';
|
import { setWriteable } from '../../state/actions/workpad';
|
||||||
import { State } from '../../../types';
|
import { State } from '../../../types';
|
||||||
import { WorkpadHeader as Component, Props as ComponentProps } from './workpad_header.component';
|
import { WorkpadHeader as Component } from './workpad_header.component';
|
||||||
|
|
||||||
interface StateProps {
|
const mapStateToProps = (state: State) => ({
|
||||||
isWriteable: boolean;
|
|
||||||
canUserWrite: boolean;
|
|
||||||
selectedPage: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DispatchProps {
|
|
||||||
setWriteable: (isWorkpadWriteable: boolean) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = (state: State): StateProps => ({
|
|
||||||
isWriteable: isWriteable(state) && canUserWrite(state),
|
isWriteable: isWriteable(state) && canUserWrite(state),
|
||||||
canUserWrite: canUserWrite(state),
|
canUserWrite: canUserWrite(state),
|
||||||
selectedPage: getSelectedPage(state),
|
selectedPage: getSelectedPage(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
const mapDispatchToProps = (dispatch: Dispatch) => ({
|
||||||
setWriteable: (isWorkpadWriteable: boolean) => dispatch(setWriteable(isWorkpadWriteable)),
|
onSetWriteable: (isWorkpadWriteable: boolean) => dispatch(setWriteable(isWorkpadWriteable)),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mergeProps = (
|
export const WorkpadHeader = connect(mapStateToProps, mapDispatchToProps)(Component);
|
||||||
stateProps: StateProps,
|
|
||||||
dispatchProps: DispatchProps,
|
|
||||||
ownProps: ComponentProps
|
|
||||||
): ComponentProps => ({
|
|
||||||
...stateProps,
|
|
||||||
...dispatchProps,
|
|
||||||
...ownProps,
|
|
||||||
toggleWriteable: () => dispatchProps.setWriteable(!stateProps.isWriteable),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const WorkpadHeader = connect(mapStateToProps, mapDispatchToProps, mergeProps)(Component);
|
|
||||||
|
|
|
@ -76,3 +76,7 @@ export interface CanvasWorkpadBoundingBox {
|
||||||
top: number;
|
top: number;
|
||||||
bottom: number;
|
bottom: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type LayoutState = any;
|
||||||
|
|
||||||
|
export type CommitFn = (type: string, payload: any) => LayoutState;
|
||||||
|
|
Loading…
Reference in a new issue