Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EPM] Packages list tabs #60167

Merged
merged 8 commits into from
Mar 17, 2020
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
2 changes: 1 addition & 1 deletion x-pack/plugins/ingest_manager/common/types/models/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { SavedObjectAttributes } from '../../../../../../src/core/public';
import { SavedObjectAttributes } from 'src/core/public';
import { AGENT_TYPE_EPHEMERAL, AGENT_TYPE_PERMANENT, AGENT_TYPE_TEMPORARY } from '../../constants';

export type AgentType =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { SavedObjectAttributes } from '../../../../../../src/core/public';
import { SavedObjectAttributes } from 'src/core/public';
import {
Datasource,
DatasourcePackage,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { SavedObjectAttributes } from '../../../../../../src/core/public';
import { SavedObjectAttributes } from 'src/core/public';

export interface EnrollmentAPIKey {
id: string;
Expand Down
6 changes: 1 addition & 5 deletions x-pack/plugins/ingest_manager/common/types/models/epm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@

// Follow pattern from https://github.com/elastic/kibana/pull/52447
// TODO: Update when https://github.com/elastic/kibana/issues/53021 is closed
import {
SavedObject,
SavedObjectAttributes,
SavedObjectReference,
} from '../../../../../../src/core/public';
import { SavedObject, SavedObjectAttributes, SavedObjectReference } from 'src/core/public';

export enum InstallationStatus {
installed = 'installed',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* 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 React, { memo } from 'react';
import styled from 'styled-components';
import { EuiFlexGroup, EuiFlexItem, EuiTabs, EuiTab, EuiSpacer } from '@elastic/eui';
import { Props as EuiTabProps } from '@elastic/eui/src/components/tabs/tab';
Expand Down Expand Up @@ -35,13 +35,17 @@ export interface HeaderProps {
tabs?: EuiTabProps[];
}

const HeaderColumns: React.FC<Omit<HeaderProps, 'tabs'>> = memo(({ leftColumn, rightColumn }) => (
<EuiFlexGroup alignItems="center">
{leftColumn ? <EuiFlexItem>{leftColumn}</EuiFlexItem> : null}
{rightColumn ? <EuiFlexItem>{rightColumn}</EuiFlexItem> : null}
</EuiFlexGroup>
));

export const Header: React.FC<HeaderProps> = ({ leftColumn, rightColumn, tabs }) => (
<Container>
<Wrapper>
<EuiFlexGroup alignItems="center">
{leftColumn ? <EuiFlexItem>{leftColumn}</EuiFlexItem> : null}
{rightColumn ? <EuiFlexItem>{rightColumn}</EuiFlexItem> : null}
</EuiFlexGroup>
<HeaderColumns leftColumn={leftColumn} rightColumn={rightColumn} />
<EuiFlexGroup>
{tabs ? (
<EuiFlexItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ export { PLUGIN_ID, EPM_API_ROUTES, AGENT_CONFIG_SAVED_OBJECT_TYPE } from '../..

export const BASE_PATH = '/app/ingestManager';
export const EPM_PATH = '/epm';
export const EPM_LIST_ALL_PACKAGES_PATH = EPM_PATH;
export const EPM_LIST_INSTALLED_PACKAGES_PATH = `${EPM_PATH}/installed`;
export const EPM_DETAIL_VIEW_PATH = `${EPM_PATH}/detail/:pkgkey/:panel?`;
export const AGENT_CONFIG_PATH = '/configs';
export const AGENT_CONFIG_DETAILS_PATH = `${AGENT_CONFIG_PATH}/`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { ChromeBreadcrumb } from '../../../../../../../../../src/core/public';
import { useCore } from '../../../hooks';
import { ChromeBreadcrumb } from 'src/core/public';
import { useCore } from './use_core';

export function useBreadcrumbs(newBreadcrumbs: ChromeBreadcrumb[]) {
const { chrome } = useCore();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import React, { useContext } from 'react';
import { CoreStart } from 'kibana/public';
import { CoreStart } from 'src/core/public';

export const CoreContext = React.createContext<CoreStart | null>(null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { HttpFetchQuery } from 'kibana/public';
import { HttpFetchQuery } from 'src/core/public';
import { useRequest, sendRequest } from './use_request';
import { agentConfigRouteService } from '../../services';
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { HttpFetchQuery } from 'kibana/public';
import { HttpFetchQuery } from 'src/core/public';
import { useRequest, sendRequest } from './use_request';
import { epmRouteService } from '../../services';
import {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { HttpSetup } from 'kibana/public';
import { HttpSetup } from 'src/core/public';
import {
SendRequestConfig,
SendRequestResponse,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useObservable } from 'react-use';
import { HashRouter as Router, Redirect, Switch, Route, RouteProps } from 'react-router-dom';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiErrorBoundary } from '@elastic/eui';
import { CoreStart, AppMountParameters } from 'kibana/public';
import { CoreStart, AppMountParameters } from 'src/core/public';
import { EuiThemeProvider } from '../../../../../legacy/common/eui_styled_components';
import {
IngestManagerSetupDeps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,76 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiText } from '@elastic/eui';
import React, { Fragment, ReactNode } from 'react';
import React, { Fragment, ReactNode, useState } from 'react';
import {
EuiFlexGrid,
EuiFlexGroup,
EuiFlexItem,
EuiSpacer,
EuiTitle,
// @ts-ignore
EuiSearchBar,
EuiText,
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { Loading } from '../../../components';
import { PackageList } from '../../../types';
import { useLocalSearch, searchIdField } from '../hooks';
import { BadgeProps, PackageCard } from './package_card';

type ListProps = {
isLoading?: boolean;
controls?: ReactNode;
title: string;
list: PackageList;
} & BadgeProps;

export function PackageListGrid({ controls, title, list, showInstalledBadge }: ListProps) {
export function PackageListGrid({
isLoading,
controls,
title,
list,
showInstalledBadge,
}: ListProps) {
const [searchTerm, setSearchTerm] = useState('');
const localSearchRef = useLocalSearch(list);

const controlsContent = <ControlsColumn title={title} controls={controls} />;
const gridContent = <GridColumn list={list} showInstalledBadge={showInstalledBadge} />;
let gridContent: JSX.Element;

if (isLoading || !localSearchRef.current) {
gridContent = <Loading />;
} else {
const filteredList = searchTerm
? list.filter(item =>
(localSearchRef.current!.search(searchTerm) as PackageList)
.map(match => match[searchIdField])
.includes(item[searchIdField])
)
: list;
gridContent = <GridColumn list={filteredList} showInstalledBadge={showInstalledBadge} />;
}

return (
<EuiFlexGroup>
<EuiFlexGroup alignItems="flexStart">
<EuiFlexItem grow={1}>{controlsContent}</EuiFlexItem>
<EuiFlexItem grow={3}>{gridContent}</EuiFlexItem>
<EuiFlexItem grow={3}>
<EuiSearchBar
query={searchTerm}
box={{
placeholder: i18n.translate('xpack.ingestManager.epmList.searchPackagesPlaceholder', {
defaultMessage: 'Search for a package',
}),
incremental: true,
}}
onChange={({ queryText: userInput }: { queryText: string }) => {
setSearchTerm(userInput);
}}
/>
<EuiSpacer />
{gridContent}
</EuiFlexItem>
</EuiFlexGroup>
);
}
Expand All @@ -34,9 +85,9 @@ interface ControlsColumnProps {
function ControlsColumn({ controls, title }: ControlsColumnProps) {
return (
<Fragment>
<EuiText>
<EuiTitle size="s">
<h2>{title}</h2>
</EuiText>
</EuiTitle>
<EuiSpacer size="l" />
<EuiFlexGroup>
<EuiFlexItem grow={2}>{controls}</EuiFlexItem>
Expand All @@ -53,11 +104,24 @@ type GridColumnProps = {
function GridColumn({ list }: GridColumnProps) {
return (
<EuiFlexGrid gutterSize="l" columns={3}>
{list.map(item => (
<EuiFlexItem key={`${item.name}-${item.version}`}>
<PackageCard {...item} />
{list.length ? (
list.map(item => (
<EuiFlexItem key={`${item.name}-${item.version}`}>
<PackageCard {...item} />
</EuiFlexItem>
))
) : (
<EuiFlexItem>
<EuiText>
<p>
<FormattedMessage
id="xpack.ingestManager.epmList.noPackagesFoundPlaceholder"
defaultMessage="No packages found"
/>
</p>
</EuiText>
</EuiFlexItem>
))}
)}
</EuiFlexGrid>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

// export { useBreadcrumbs } from './use_breadcrumbs';
export { useLinks } from './use_links';
export { useLocalSearch, searchIdField } from './use_local_search';
export {
PackageInstallProvider,
useDeletePackage,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* 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 { Search as LocalSearch } from 'js-search';
import { useEffect, useRef } from 'react';
import { PackageList, PackageListItem } from '../../../types';

export type SearchField = keyof PackageListItem;
export const searchIdField: SearchField = 'name';
export const fieldsToSearch: SearchField[] = ['description', 'name', 'title'];

export function useLocalSearch(packageList: PackageList) {
const localSearchRef = useRef<LocalSearch | null>(null);

useEffect(() => {
if (!packageList.length) return;

const localSearch = new LocalSearch(searchIdField);
fieldsToSearch.forEach(field => localSearch.addIndex(field));
localSearch.addDocuments(packageList);
localSearchRef.current = localSearch;
}, [packageList]);

return localSearchRef;
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import React from 'react';
import { HashRouter as Router, Switch, Route } from 'react-router-dom';
import { useConfig } from '../../hooks';
import { CreateDatasourcePage } from '../agent_config/create_datasource_page';
import { Home } from './screens/home';
import { EPMHomePage } from './screens/home';
import { Detail } from './screens/detail';

export const EPMApp: React.FunctionComponent = () => {
Expand All @@ -23,8 +23,8 @@ export const EPMApp: React.FunctionComponent = () => {
<Route path="/epm/detail/:pkgkey/:panel?">
<Detail />
</Route>
<Route path="/epm/">
<Home />
<Route path="/epm/:tabId?" exact={true}>
<EPMHomePage />
</Route>
</Switch>
</Router>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ export function Header(props: HeaderProps) {
const { iconType, name, title, version } = props;
const hasWriteCapabilites = useCapabilities().write;
const { toListView } = useLinks();
// useBreadcrumbs([{ text: PLUGIN.TITLE, href: toListView() }, { text: title }]);

const ADD_DATASOURCE_URI = useLink(`${EPM_PATH}/${name}-${version}/add-datasource`);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,37 @@
*/
import { EuiFacetButton, EuiFacetGroup } from '@elastic/eui';
import React from 'react';
import { Loading } from '../../../../components';
import { CategorySummaryItem, CategorySummaryList } from '../../../../types';

export function CategoryFacets({
isLoading,
categories,
selectedCategory,
onCategoryChange,
}: {
isLoading?: boolean;
categories: CategorySummaryList;
selectedCategory: string;
onCategoryChange: (category: CategorySummaryItem) => unknown;
}) {
const controls = (
<EuiFacetGroup>
{categories.map(category => (
<EuiFacetButton
isSelected={category.id === selectedCategory}
key={category.id}
id={category.id}
quantity={category.count}
onClick={() => onCategoryChange(category)}
>
{category.title}
</EuiFacetButton>
))}
{isLoading ? (
<Loading />
) : (
categories.map(category => (
<EuiFacetButton
isSelected={category.id === selectedCategory}
key={category.id}
id={category.id}
quantity={category.count}
onClick={() => onCategoryChange(category)}
>
{category.title}
</EuiFacetButton>
))
)}
</EuiFacetGroup>
);

Expand Down
Loading