Skip to content

Commit

Permalink
add first page of add data source
Browse files Browse the repository at this point in the history
  • Loading branch information
neptunian committed Dec 9, 2019
1 parent 39308fe commit 76a525c
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,19 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiButtonEmpty, EuiButtonEmptyProps } from '@elastic/eui';
import React from 'react';
import { EuiButtonEmpty } from '@elastic/eui';
import styled from 'styled-components';
import { useCore, useLinks } from '../../hooks';
import React from 'react';
import { useCore } from '../hooks';

export function NavButtonBack() {
const { toListView } = useLinks();
export function NavButtonBack({ href, text }: { href: string; text: string }) {
const { theme } = useCore();
const ButtonEmpty = styled(EuiButtonEmpty).attrs<EuiButtonEmptyProps>({
href: toListView(),
})`
const ButtonEmpty = styled(EuiButtonEmpty)`
margin-right: ${theme.eui.spacerSizes.xl};
`;

return (
<ButtonEmpty iconType="arrowLeft" size="xs" flush="left">
Browse Packages
<ButtonEmpty iconType="arrowLeft" size="xs" flush="left" href={href}>
{text}
</ButtonEmpty>
);
}
10 changes: 9 additions & 1 deletion x-pack/legacy/plugins/epm/public/hooks/use_links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
*/

import { generatePath } from 'react-router-dom';
import { useCore } from '.';
import { PLUGIN } from '../../common/constants';
import { getFilePath, getInfoPath } from '../../common/routes';
import { patterns } from '../routes';
import { useCore } from '.';
import { DetailViewPanelName } from '..';

// TODO: get this from server/packages/handlers.ts (move elsewhere?)
Expand Down Expand Up @@ -53,5 +53,13 @@ export function useLinks() {
const params = Object.assign({ pkgkey: `${name}-${version}` }, panel ? { panel } : {});
return appRoot(generatePath(patterns.DETAIL_VIEW, params));
},
toDetailViewRelative: ({ name, version, panel }: DetailParams) => {
// panel is optional, but `generatePath` won't accept `path: undefined`
// so use this to pass `{ pkgkey }` or `{ pkgkey, panel }`
const params = Object.assign({ pkgkey: `${name}-${version}` }, panel ? { panel } : {});
return generatePath(patterns.DETAIL_VIEW, params);
},
toAddDataSourceView: ({ name, version }: { name: string; version: string }) =>
appRoot(generatePath(patterns.ADD_DATA_SOURCE_VIEW, { pkgkey: `${name}-${version}` })),
};
}
23 changes: 9 additions & 14 deletions x-pack/legacy/plugins/epm/public/hooks/use_package_install.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { EuiButton, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import React, { useCallback, useState, Fragment } from 'react';
import createContainer from 'constate';
import React, { Fragment, useCallback, useState } from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiButton } from '@elastic/eui';
import { NotificationsStart } from 'src/core/public';
import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public';
import { PackageInfo } from '../../common/types';
import { installDatasource, installPackage as fetchInstallPackage, removePackage } from '../data';
import { installPackage as fetchInstallPackage, removePackage } from '../data';
import { InstallStatus } from '../types';
import { useLinks } from '.';

interface PackagesInstall {
[key: string]: PackageInstallItem;
Expand All @@ -23,6 +24,7 @@ interface PackageInstallItem {

function usePackageInstall({ notifications }: { notifications: NotificationsStart }) {
const [packages, setPackage] = useState<PackagesInstall>({});
const { toAddDataSourceView } = useLinks();

const setPackageInstallStatus = useCallback(
({ name, status }: { name: PackageInfo['name']; status: InstallStatus }) => {
Expand All @@ -38,26 +40,19 @@ function usePackageInstall({ notifications }: { notifications: NotificationsStar
async ({ name, version, title }: Pick<PackageInfo, 'name' | 'version' | 'title'>) => {
setPackageInstallStatus({ name, status: InstallStatus.installing });
const pkgkey = `${name}-${version}`;
const handleRequestInstallDatasource = () => {
installDatasource(pkgkey).then(() => {
notifications.toasts.addSuccess({
title: `Installed Datasource`,
text: 'Successfully installed Datasource',
});
});
};

try {
await fetchInstallPackage(pkgkey);
setPackageInstallStatus({ name, status: InstallStatus.installed });

const packageDataSourceUrl = toAddDataSourceView({ name, version });
const SuccessMsg = (
<Fragment>
<p>Next, create a data source to begin sending data to your Elasticsearch cluster.</p>
<EuiFlexGroup justifyContent="flexEnd" gutterSize="s">
<EuiFlexItem grow={false}>
{/* Would like to add a loading indicator here but, afaict,
notifications are static. i.e. they won't re-render with new state */}
<EuiButton onClick={handleRequestInstallDatasource} size="s">
<EuiButton href={packageDataSourceUrl} size="s">
Add data source
</EuiButton>
</EuiFlexItem>
Expand All @@ -79,7 +74,7 @@ function usePackageInstall({ notifications }: { notifications: NotificationsStar
});
}
},
[notifications.toasts, setPackageInstallStatus]
[notifications.toasts, setPackageInstallStatus, toAddDataSourceView]
);

const getPackageInstallStatus = useCallback(
Expand Down
16 changes: 15 additions & 1 deletion x-pack/legacy/plugins/epm/public/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@

import React from 'react';
import { Route } from 'react-router-dom';
import { PLUGIN } from '../common/constants';
import { Detail, DetailProps } from './screens/detail';
import { AddDataSource, AddDataSourceProps } from './screens/add_data_source';
import { Home } from './screens/home';
import { PLUGIN } from '../common/constants';

// patterns are used by React Router and are relative to `APP_ROOT`
export const patterns = {
APP_ROOT: `/app/${PLUGIN.ID}`,
LIST_VIEW: '/',
DETAIL_VIEW: '/detail/:pkgkey/:panel?',
ADD_DATA_SOURCE_VIEW: '/add-data-source/:pkgkey',
};

export const routes = [
Expand All @@ -25,10 +27,22 @@ export const routes = [
exact={true}
render={(props: DetailMatch) => <Detail {...props.match.params} />}
/>,
<Route
key="add-data-source"
path={patterns.ADD_DATA_SOURCE_VIEW}
exact={true}
render={(props: AddDataSourceMatch) => <AddDataSource {...props.match.params} />}
/>,
];

interface DetailMatch {
match: {
params: DetailProps;
};
}

interface AddDataSourceMatch {
match: {
params: AddDataSourceProps;
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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, { useState, Fragment, useCallback } from 'react';
import styled from 'styled-components';
import { EuiPanel, EuiSteps, EuiButton, EuiHorizontalRule } from '@elastic/eui';
import { Redirect } from 'react-router-dom';
import { StepOneTemplate } from './step_one';
import { installDatasource } from '../../data';
import { useCore, useLinks } from '../../hooks';

const StyledSteps = styled.div`
.euiStep__titleWrapper {
border-bottom: 1px solid ${props => props.theme.eui.euiBorderColor};
padding-bottom: ${props => props.theme.eui.paddingSizes.l};
}
.euiStep__content {
padding-bottom: 0;
}
`;
interface AddDataSourceStepsProps {
pkgName: string;
pkgTitle: string;
pkgVersion: string;
}
const FormNav = styled.div`
text-align: right;
`;
export const AddDataSourceSteps = (props: AddDataSourceStepsProps) => {
const [addDataSourceSuccess, setAddDataSourceSuccess] = useState<boolean>(false);
const { notifications } = useCore();
const { toDetailViewRelative } = useLinks();
const { pkgName, pkgTitle, pkgVersion } = props;
const handleRequestInstallDatasource = useCallback(async () => {
try {
await installDatasource(`${pkgName}-${pkgVersion}`);
setAddDataSourceSuccess(true);
notifications.toasts.addSuccess({
title: `Added ${pkgTitle} data source`,
});
return;
} catch (err) {
notifications.toasts.addWarning({
title: `Failed to add data source to ${pkgTitle}`,
iconType: 'alert',
});
}
}, [notifications.toasts, pkgName, pkgTitle, pkgVersion]);
const stepOne = [
{
title: 'Define your data source',
children: <StepOneTemplate />,
},
];

return (
<Fragment>
{addDataSourceSuccess ? (
<Redirect
to={toDetailViewRelative({ name: pkgName, version: pkgVersion, panel: 'data-sources' })}
/>
) : (
<EuiPanel>
<StyledSteps>
<EuiSteps steps={stepOne} />
</StyledSteps>
<FormNav>
<EuiHorizontalRule margin="xl" />
<EuiButton fill onClick={handleRequestInstallDatasource}>
Continue
</EuiButton>
</FormNav>
</EuiPanel>
)}
</Fragment>
);
};
84 changes: 84 additions & 0 deletions x-pack/legacy/plugins/epm/public/screens/add_data_source/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* 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, { useState, useEffect } from 'react';
import { ICON_TYPES, EuiPageHeader, EuiTitle, EuiFlexGroup, EuiIcon, EuiPanel } from '@elastic/eui';
import styled from 'styled-components';
import { NavButtonBack } from '../../components/nav_button_back';
import { useLinks } from '../../hooks';
import { PackageInfo } from '../../../common/types';
import { getPackageInfoByKey } from '../../data';
import { AddDataSourceSteps } from './add_data_source_steps';

export interface AddDataSourceProps {
pkgkey: string;
}

// TODO: change to percentages?
const SIDEBAR_WIDTH = '168px';

const PageContainer = styled.div`
margin: 0 auto;
min-width: 1200px;
`;
const PageBody = styled.div`
max-width: 772px;
`;
const NavButtonBackWrapper = styled.div`
padding: ${props => props.theme.eui.paddingSizes.xl} 0 ${props => props.theme.eui.paddingSizes.m}
0;
`;
const SideBar = styled.div`
margin-right: ${props => props.theme.eui.paddingSizes.xl};
max-width: ${SIDEBAR_WIDTH};
`;
const IconPanel = styled(EuiPanel)`
padding: ${props => props.theme.eui.paddingSizes.xl} !important;
text-align: center;
width: ${SIDEBAR_WIDTH};
height: ${SIDEBAR_WIDTH};
`;
export function AddDataSource({ pkgkey }: AddDataSourceProps) {
const [info, setInfo] = useState<PackageInfo | null>(null);
const { toDetailView } = useLinks();

useEffect(() => {
getPackageInfoByKey(pkgkey).then(response => {
setInfo({ ...response });
});
}, [pkgkey]);

// don't have designs for loading/empty states
if (!info) return null;

const { version, name, title } = info;
const iconType = ICON_TYPES.find(key => key.toLowerCase() === `logo${name}`);

return (
<PageContainer>
<NavButtonBackWrapper>
<NavButtonBack
href={toDetailView({ name, panel: 'data-sources', version })}
text="Cancel"
/>
</NavButtonBackWrapper>
<EuiFlexGroup gutterSize="none">
<SideBar>
<IconPanel>
{iconType ? <EuiIcon width="102" height="102" type={iconType} size="original" /> : null}
</IconPanel>
</SideBar>
<PageBody>
<EuiPageHeader>
<EuiTitle size="l">
<h1>Add {title} data source</h1>
</EuiTitle>
</EuiPageHeader>
<AddDataSourceSteps pkgName={name} pkgVersion={version} pkgTitle={title} />
</PageBody>
</EuiFlexGroup>
</PageContainer>
);
}
Loading

0 comments on commit 76a525c

Please sign in to comment.