mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
* Extract Tags component and tag filter config object from workpad templates Added tag filtering to element selection modal Added tags to element Added type definitions to Registry in @kbn/interpreter Added stories for Tag and TagList components Changed graphic tag color
This commit is contained in:
parent
688892e13c
commit
7448f64e1d
65 changed files with 1442 additions and 117 deletions
20
packages/kbn-interpreter/src/common/index.d.ts
vendored
Normal file
20
packages/kbn-interpreter/src/common/index.d.ts
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { Registry } from './lib/registry';
|
36
packages/kbn-interpreter/src/common/lib/registry.d.ts
vendored
Normal file
36
packages/kbn-interpreter/src/common/lib/registry.d.ts
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export class Registry<ItemSpec, Item> {
|
||||
constructor(prop?: string);
|
||||
|
||||
public wrapper(obj: ItemSpec): Item;
|
||||
|
||||
public register(fn: () => ItemSpec): void;
|
||||
|
||||
public toJS(): { [key: string]: any };
|
||||
|
||||
public toArray(): Item[];
|
||||
|
||||
public get(name: string): Item;
|
||||
|
||||
public getProp(): string;
|
||||
|
||||
public reset(): void;
|
||||
}
|
4
packages/kbn-interpreter/tsconfig.json
Normal file
4
packages/kbn-interpreter/tsconfig.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["index.d.ts", "src/**/*.d.ts"]
|
||||
}
|
|
@ -11,6 +11,7 @@ export const areaChart: ElementFactory = () => ({
|
|||
name: 'areaChart',
|
||||
displayName: 'Area chart',
|
||||
help: 'A line chart with a filled body',
|
||||
tags: ['chart'],
|
||||
image: header,
|
||||
expression: `filters
|
||||
| demodata
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const bubbleChart: ElementFactory = () => ({
|
||||
name: 'bubbleChart',
|
||||
displayName: 'Bubble chart',
|
||||
tags: ['chart'],
|
||||
help: 'A customizable bubble chart',
|
||||
width: 700,
|
||||
height: 300,
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const debug: ElementFactory = () => ({
|
||||
name: 'debug',
|
||||
displayName: 'Debug',
|
||||
tags: ['text'],
|
||||
help: 'Just dumps the configuration of the element',
|
||||
image: header,
|
||||
expression: `demodata
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const donut: ElementFactory = () => ({
|
||||
name: 'donut',
|
||||
displayName: 'Donut chart',
|
||||
tags: ['chart', 'proportion'],
|
||||
help: 'A customizable donut chart',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const dropdownFilter: ElementFactory = () => ({
|
||||
name: 'dropdown_filter',
|
||||
displayName: 'Dropdown filter',
|
||||
tags: ['filter'],
|
||||
help: 'A dropdown from which you can select values for an "exactly" filter',
|
||||
image: header,
|
||||
height: 50,
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const horizontalBarChart: ElementFactory = () => ({
|
||||
name: 'horizontalBarChart',
|
||||
displayName: 'Horizontal bar chart',
|
||||
tags: ['chart'],
|
||||
help: 'A customizable horizontal bar chart',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -11,6 +11,7 @@ import header from './header.png';
|
|||
export const horizontalProgressBar: ElementFactory = () => ({
|
||||
name: 'horizontalProgressBar',
|
||||
displayName: 'Horizontal progress bar',
|
||||
tags: ['chart', 'proportion'],
|
||||
help: 'Displays progress as a portion of a horizontal bar',
|
||||
width: 400,
|
||||
height: 30,
|
||||
|
|
|
@ -11,6 +11,7 @@ import header from './header.png';
|
|||
export const horizontalProgressPill: ElementFactory = () => ({
|
||||
name: 'horizontalProgressPill',
|
||||
displayName: 'Horizontal progress pill',
|
||||
tags: ['chart', 'proportion'],
|
||||
help: 'Displays progress as a portion of a horizontal pill',
|
||||
width: 400,
|
||||
height: 30,
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const image: ElementFactory = () => ({
|
||||
name: 'image',
|
||||
displayName: 'Image',
|
||||
tags: ['graphic'],
|
||||
help: 'A static image',
|
||||
image: header,
|
||||
expression: `image dataurl=null mode="contain"
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const lineChart: ElementFactory = () => ({
|
||||
name: 'lineChart',
|
||||
displayName: 'Line chart',
|
||||
tags: ['chart'],
|
||||
help: 'A customizable line chart',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -10,6 +10,7 @@ import { ElementFactory } from '../types';
|
|||
export const markdown: ElementFactory = () => ({
|
||||
name: 'markdown',
|
||||
displayName: 'Markdown',
|
||||
tags: ['text'],
|
||||
help: 'Markup from Markdown',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -11,6 +11,7 @@ import { ElementFactory } from '../types';
|
|||
export const metric: ElementFactory = () => ({
|
||||
name: 'metric',
|
||||
displayName: 'Metric',
|
||||
tags: ['text'],
|
||||
help: 'A number with a label',
|
||||
width: 200,
|
||||
height: 100,
|
||||
|
|
|
@ -10,6 +10,7 @@ import { ElementFactory } from '../types';
|
|||
export const pie: ElementFactory = () => ({
|
||||
name: 'pie',
|
||||
displayName: 'Pie chart',
|
||||
tags: ['chart', 'proportion'],
|
||||
width: 300,
|
||||
height: 300,
|
||||
help: 'A simple pie chart',
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const plot: ElementFactory = () => ({
|
||||
name: 'plot',
|
||||
displayName: 'Coordinate plot',
|
||||
tags: ['chart'],
|
||||
help: 'Mixed line, bar or dot charts',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -11,6 +11,7 @@ import header from './header.png';
|
|||
export const progressGauge: ElementFactory = () => ({
|
||||
name: 'progressGauge',
|
||||
displayName: 'Progress gauge',
|
||||
tags: ['chart', 'proportion'],
|
||||
help: 'Displays progress as a portion of a gauge',
|
||||
width: 200,
|
||||
height: 200,
|
||||
|
|
|
@ -11,6 +11,7 @@ import header from './header.png';
|
|||
export const progressSemicircle: ElementFactory = () => ({
|
||||
name: 'progressSemicircle',
|
||||
displayName: 'Progress semicircle',
|
||||
tags: ['chart', 'proportion'],
|
||||
help: 'Displays progress as a portion of a semicircle',
|
||||
width: 200,
|
||||
height: 100,
|
||||
|
|
|
@ -11,6 +11,7 @@ import header from './header.png';
|
|||
export const progressWheel: ElementFactory = () => ({
|
||||
name: 'progressWheel',
|
||||
displayName: 'Progress wheel',
|
||||
tags: ['chart', 'proportion'],
|
||||
help: 'Displays progress as a portion of a wheel',
|
||||
width: 200,
|
||||
height: 200,
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const repeatImage: ElementFactory = () => ({
|
||||
name: 'repeatImage',
|
||||
displayName: 'Image repeat',
|
||||
tags: ['graphic', 'proportion'],
|
||||
help: 'Repeats an image N times',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const revealImage: ElementFactory = () => ({
|
||||
name: 'revealImage',
|
||||
displayName: 'Image reveal',
|
||||
tags: ['graphic', 'proportion'],
|
||||
help: 'Reveals a percentage of an image',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const shape: ElementFactory = () => ({
|
||||
name: 'shape',
|
||||
displayName: 'Shape',
|
||||
tags: ['graphic'],
|
||||
help: 'A customizable shape',
|
||||
width: 200,
|
||||
height: 200,
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const table: ElementFactory = () => ({
|
||||
name: 'table',
|
||||
displayName: 'Data table',
|
||||
tags: ['text'],
|
||||
help: 'A scrollable grid for displaying data in a tabular format',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const tiltedPie: ElementFactory = () => ({
|
||||
name: 'tiltedPie',
|
||||
displayName: 'Tilted pie chart',
|
||||
tags: ['chart', 'proportion'],
|
||||
width: 500,
|
||||
height: 250,
|
||||
help: 'A customizable tilted pie chart',
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const timeFilter: ElementFactory = () => ({
|
||||
name: 'time_filter',
|
||||
displayName: 'Time filter',
|
||||
tags: ['filter'],
|
||||
help: 'Set a time window',
|
||||
image: header,
|
||||
height: 50,
|
||||
|
|
|
@ -9,6 +9,7 @@ export interface ElementSpec {
|
|||
image: string;
|
||||
expression: string;
|
||||
displayName?: string;
|
||||
tags?: string[];
|
||||
help?: string;
|
||||
filter?: string;
|
||||
width?: number;
|
||||
|
|
|
@ -10,6 +10,7 @@ import header from './header.png';
|
|||
export const verticalBarChart: ElementFactory = () => ({
|
||||
name: 'verticalBarChart',
|
||||
displayName: 'Vertical bar chart',
|
||||
tags: ['chart'],
|
||||
help: 'A customizable vertical bar chart',
|
||||
image: header,
|
||||
expression: `filters
|
||||
|
|
|
@ -11,6 +11,7 @@ import header from './header.png';
|
|||
export const verticalProgressBar: ElementFactory = () => ({
|
||||
name: 'verticalProgressBar',
|
||||
displayName: 'Vertical progress bar',
|
||||
tags: ['chart', 'proportion'],
|
||||
help: 'Displays progress as a portion of a vertical bar',
|
||||
width: 80,
|
||||
height: 400,
|
||||
|
|
|
@ -11,6 +11,7 @@ import header from './header.png';
|
|||
export const verticalProgressPill: ElementFactory = () => ({
|
||||
name: 'verticalProgressPill',
|
||||
displayName: 'Vertical progress pill',
|
||||
tags: ['chart', 'proportion'],
|
||||
help: 'Displays progress as a portion of a vertical pill',
|
||||
width: 80,
|
||||
height: 400,
|
||||
|
|
|
@ -4,10 +4,6 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export function Tag(config) {
|
||||
// The name of the tag
|
||||
this.name = config.name;
|
||||
import { TagFactory } from '../../../public/lib/tag';
|
||||
|
||||
// color of the tag to display in a list
|
||||
this.color = config.color;
|
||||
}
|
||||
export const chart: TagFactory = () => ({ name: 'chart', color: '#FEB6DB' });
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 { TagFactory } from '../../../public/lib/tag';
|
||||
|
||||
export const filter: TagFactory = () => ({ name: 'filter', color: '#3185FC' });
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 { TagFactory } from '../../../public/lib/tag';
|
||||
|
||||
export const graphic: TagFactory = () => ({ name: 'graphic', color: '#E6C220' });
|
|
@ -4,8 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { chart } from './chart';
|
||||
import { filter } from './filter';
|
||||
import { graphic } from './graphic';
|
||||
import { presentation } from './presentation';
|
||||
import { proportion } from './proportion';
|
||||
import { report } from './report';
|
||||
import { text } from './text';
|
||||
|
||||
// Registry expects a function that returns a spec object
|
||||
export const tagSpecs = [presentation, report];
|
||||
export const tagSpecs = [chart, filter, graphic, presentation, proportion, report, text];
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 { TagFactory } from '../../../public/lib/tag';
|
||||
|
||||
export const presentation: TagFactory = () => ({ name: 'presentation', color: '#017D73' });
|
|
@ -4,4 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const presentation = () => ({ name: 'presentation', color: '#1EA593' });
|
||||
export const proportion = () => ({ name: 'proportion', color: '#490092' });
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 { TagFactory } from '../../../public/lib/tag';
|
||||
|
||||
export const proportion: TagFactory = () => ({ name: 'proportion', color: '#490092' });
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 { TagFactory } from '../../../public/lib/tag';
|
||||
|
||||
export const report: TagFactory = () => ({ name: 'report', color: '#DB1374' });
|
9
x-pack/plugins/canvas/canvas_plugin_src/uis/tags/text.ts
Normal file
9
x-pack/plugins/canvas/canvas_plugin_src/uis/tags/text.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 { TagFactory } from '../../../public/lib/tag';
|
||||
|
||||
export const text: TagFactory = () => ({ name: 'text', color: '#D3DAE6' });
|
|
@ -103,6 +103,179 @@ exports[`Storyshots components/ElementCard with image 1`] = `
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/ElementCard with tags 1`] = `
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"width": "210px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<button
|
||||
className="euiCard euiCard--leftAligned euiCard--isClickable euiCard--hasIcon canvasElementCard canvasElementCard--hasIcon"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<span
|
||||
className="euiCard__top"
|
||||
>
|
||||
<svg
|
||||
className="euiIcon euiIcon--xxLarge euiIcon--app euiCard__icon"
|
||||
focusable="false"
|
||||
height="32"
|
||||
style={null}
|
||||
viewBox="0 0 32 32"
|
||||
width="32"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
className="euiIcon__fillSecondary"
|
||||
d="M7 17h2v7H7zM12 14h2v10h-2zM17 16h2v8h-2zM22 14h3v2h-3zM22 18h3v2h-3zM22 22h3v2h-3z"
|
||||
/>
|
||||
<path
|
||||
d="M30.73 24a6.47 6.47 0 0 1 .45-2.19c.337-.9.52-1.85.54-2.81a8.55 8.55 0 0 0-.54-2.81 6.47 6.47 0 0 1-.45-2.19 9.2 9.2 0 0 1 .62-2.49c.53-1.57 1.08-3.19.08-4.2-1-1.01-2.41-.44-3.52.05a5.59 5.59 0 0 1-2.09.64 5.3 5.3 0 0 1-.59 0L16 .28 6.77 8a5.3 5.3 0 0 1-.59 0 5.59 5.59 0 0 1-2.09-.65C3 6.87 1.6 6.25.57 7.31c-1.03 1.06-.45 2.63.08 4.2A9.2 9.2 0 0 1 1.27 14a6.47 6.47 0 0 1-.45 2.19A8.55 8.55 0 0 0 .28 19c.02.96.203 1.91.54 2.81A6.47 6.47 0 0 1 1.27 24a9.2 9.2 0 0 1-.62 2.49c-.53 1.57-1.08 3.19-.08 4.2.353.38.852.59 1.37.58a5.67 5.67 0 0 0 2.15-.63A5.59 5.59 0 0 1 6.18 30a7.13 7.13 0 0 1 2.29.47 8 8 0 0 0 2.62.53 7.37 7.37 0 0 0 2.47-.51A7.14 7.14 0 0 1 16 30a6.24 6.24 0 0 1 2.14.45 8 8 0 0 0 2.77.55 8.08 8.08 0 0 0 2.77-.55 6.24 6.24 0 0 1 2.14-.45 5.59 5.59 0 0 1 2.09.65c1.11.49 2.49 1.11 3.52.05 1.03-1.06.45-2.63-.08-4.2a9.2 9.2 0 0 1-.62-2.5zM21.17 7h-.26a8 8 0 0 0-2.77.55A6.24 6.24 0 0 1 16 8a6.24 6.24 0 0 1-2.14-.45A8 8 0 0 0 11.09 7h-.26L16 2.72 21.17 7zm8.89 22.27a4.42 4.42 0 0 1-1.34-.46 7.08 7.08 0 0 0-2.9-.82 8.14 8.14 0 0 0-2.78.55 6.13 6.13 0 0 1-2.13.45 6.24 6.24 0 0 1-2.14-.45A8 8 0 0 0 16 28a9 9 0 0 0-3.08.6 5.74 5.74 0 0 1-1.83.4 6.36 6.36 0 0 1-2-.43A8.72 8.72 0 0 0 6.18 28a7.08 7.08 0 0 0-2.9.82 9.65 9.65 0 0 1-1.28.52 6.08 6.08 0 0 1 .52-2.21c.403-1 .65-2.055.73-3.13a8.55 8.55 0 0 0-.54-2.81A6.47 6.47 0 0 1 2.27 19a6.47 6.47 0 0 1 .44-2.19c.337-.9.52-1.85.54-2.81a10.48 10.48 0 0 0-.72-3.13 9 9 0 0 1-.59-2.16H2c.447.1.88.255 1.29.46a7.08 7.08 0 0 0 2.9.82A8.14 8.14 0 0 0 9 9.44 6.13 6.13 0 0 1 11.09 9a6.13 6.13 0 0 1 2.13.45A8.14 8.14 0 0 0 16 10a8.14 8.14 0 0 0 2.78-.55A6.13 6.13 0 0 1 20.91 9a6.13 6.13 0 0 1 2.09.44 8.14 8.14 0 0 0 2.78.55 7.08 7.08 0 0 0 2.9-.82A9.65 9.65 0 0 1 30 8.66a6.08 6.08 0 0 1-.52 2.21c-.403 1-.65 2.055-.73 3.13.02.96.203 1.91.54 2.81a6.47 6.47 0 0 1 .44 2.19 6.47 6.47 0 0 1-.44 2.19 8.55 8.55 0 0 0-.54 2.81c.078 1.074.32 2.13.72 3.13a9 9 0 0 1 .59 2.16v-.02z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
className="euiCard__content"
|
||||
>
|
||||
<span
|
||||
className="euiTitle euiTitle--medium euiCard__title"
|
||||
id="generated-idTitle"
|
||||
>
|
||||
Element 1
|
||||
</span>
|
||||
<div
|
||||
className="euiText euiText--small euiCard__description"
|
||||
id="generated-idDescription"
|
||||
>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lobortis aliquet arcu ut turpis duis.
|
||||
</p>
|
||||
</div>
|
||||
</span>
|
||||
<span
|
||||
className="euiCard__footer"
|
||||
>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag1
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag2
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag3
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag4
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag5
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag6
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/ElementCard with title and description 1`] = `
|
||||
<div
|
||||
style={
|
||||
|
|
|
@ -33,6 +33,14 @@ storiesOf('components/ElementCard', module)
|
|||
image={elasticLogo}
|
||||
/>
|
||||
))
|
||||
.add('with tags', () => (
|
||||
<ElementCard
|
||||
title="Element 1"
|
||||
description="Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lobortis aliquet arcu ut turpis duis."
|
||||
tags={['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6']}
|
||||
onClick={action('onClick')}
|
||||
/>
|
||||
))
|
||||
.add('with click handler', () => (
|
||||
<ElementCard
|
||||
title="Element 1"
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
EuiCard,
|
||||
EuiIcon,
|
||||
} from '@elastic/eui';
|
||||
import { TagList } from '../tag_list/';
|
||||
|
||||
export interface Props {
|
||||
/**
|
||||
|
@ -24,18 +25,25 @@ export interface Props {
|
|||
* preview image of the element
|
||||
*/
|
||||
image?: string;
|
||||
/**
|
||||
* tags associated with the element
|
||||
*/
|
||||
tags?: string[];
|
||||
/**
|
||||
* handler when clicking the card
|
||||
*/
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const ElementCard = ({ title, description, image, onClick, ...rest }: Props) => (
|
||||
const tagType = 'badge';
|
||||
|
||||
export const ElementCard = ({ title, description, image, tags = [], onClick, ...rest }: Props) => (
|
||||
<EuiCard
|
||||
className={image ? 'canvasElementCard' : 'canvasElementCard canvasElementCard--hasIcon'}
|
||||
textAlign="left"
|
||||
title={title}
|
||||
description={description}
|
||||
footer={<TagList tags={tags} tagType={tagType} />}
|
||||
image={image}
|
||||
icon={image ? null : <EuiIcon type="canvasApp" size="xxl" />}
|
||||
onClick={onClick}
|
||||
|
|
|
@ -530,7 +530,81 @@ exports[`Storyshots components/ElementTypes/ElementGrid with controls and filter
|
|||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/ElementTypes/ElementGrid with filter 1`] = `
|
||||
exports[`Storyshots components/ElementTypes/ElementGrid with tags filter 1`] = `
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"width": "1000px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="euiFlexGrid euiFlexGrid--gutterLarge euiFlexGrid--fourths euiFlexGrid--responsive"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem canvasElementCard__wrapper"
|
||||
>
|
||||
<button
|
||||
className="euiCard euiCard--leftAligned euiCard--isClickable canvasElementCard"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<span
|
||||
className="euiCard__top"
|
||||
>
|
||||
<img
|
||||
alt=""
|
||||
className="euiCard__image"
|
||||
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmlld0JveD0iMCAwIDI3MC42MDAwMSAyNjkuNTQ2NjYiCiAgIGhlaWdodD0iMjY5LjU0NjY2IgogICB3aWR0aD0iMjcwLjYwMDAxIgogICB4bWw6c3BhY2U9InByZXNlcnZlIgogICBpZD0ic3ZnMiIKICAgdmVyc2lvbj0iMS4xIj48bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE4Ij48cmRmOlJERj48Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+PGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+PGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPjwvY2M6V29yaz48L3JkZjpSREY+PC9tZXRhZGF0YT48ZGVmcwogICAgIGlkPSJkZWZzNiIgLz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMzMzMzMzMywwLDAsLTEuMzMzMzMzMywwLDI2OS41NDY2NykiCiAgICAgaWQ9ImcxMCI+PGcKICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMC4xKSIKICAgICAgIGlkPSJnMTIiPjxwYXRoCiAgICAgICAgIGlkPSJwYXRoMTQiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiCiAgICAgICAgIGQ9Im0gMjAyOS40OCw5NjIuNDQxIGMgMCwxNzAuMDk5IC0xMDUuNDYsMzE4Ljc5OSAtMjY0LjE3LDM3Ni42NTkgNi45OCwzNS44NiAxMC42Miw3MS43MSAxMC42MiwxMDkuMDUgMCwzMTYuMTkgLTI1Ny4yNCw1NzMuNDMgLTU3My40Nyw1NzMuNDMgLTE4NC43MiwwIC0zNTYuNTU4LC04OC41OSAtNDY0LjUzLC0yMzcuODUgLTUzLjA5LDQxLjE4IC0xMTguMjg1LDYzLjc1IC0xODYuMzA1LDYzLjc1IC0xNjcuODM2LDAgLTMwNC4zODMsLTEzNi41NCAtMzA0LjM4MywtMzA0LjM4IDAsLTM3LjA4IDYuNjE3LC03Mi41OCAxOS4wMzEsLTEwNi4wOCBDIDEwOC40ODgsMTM4MC4wOSAwLDEyMjcuODkgMCwxMDU4Ljg4IDAsODg3LjkxIDEwNS45NzcsNzM4LjUzOSAyNjUuMzk4LDY4MS4wOSBjIC02Ljc2OSwtMzUuNDQyIC0xMC40NiwtNzIuMDIgLTEwLjQ2LC0xMDkgQyAyNTQuOTM4LDI1Ni42MjEgNTExLjU2NiwwIDgyNy4wMjcsMCAxMDEyLjIsMCAxMTgzLjk0LDg4Ljk0MTQgMTI5MS4zLDIzOC44MzIgYyA1My40NSwtNDEuOTYxIDExOC44LC02NC45OTIgMTg2LjU2LC02NC45OTIgMTY3LjgzLDAgMzA0LjM4LDEzNi40OTIgMzA0LjM4LDMwNC4zMzIgMCwzNy4wNzggLTYuNjIsNzIuNjI5IC0xOS4wMywxMDYuMTI5IDE1Ny43OCw1Ni44NzkgMjY2LjI3LDIwOS4xMjkgMjY2LjI3LDM3OC4xNCIgLz48cGF0aAogICAgICAgICBpZD0icGF0aDE2IgogICAgICAgICBzdHlsZT0iZmlsbDojZmFjZjA5O2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIgogICAgICAgICBkPSJtIDc5Ny44OTgsMTE1MC45MyA0NDQuMDcyLC0yMDIuNDUgNDQ4LjA1LDM5Mi41OCBjIDYuNDksMzIuMzkgOS42Niw2NC42NyA5LjY2LDk4LjQ2IDAsMjc2LjIzIC0yMjQuNjgsNTAwLjk1IC01MDAuOSw1MDAuOTUgLTE2NS4yNCwwIC0zMTkuMzcsLTgxLjM2IC00MTMuMDUzLC0yMTcuNzkgbCAtNzQuNTI0LC0zODYuNjQgODYuNjk1LC0xODUuMTEiIC8+PHBhdGgKICAgICAgICAgaWQ9InBhdGgxOCIKICAgICAgICAgc3R5bGU9ImZpbGw6IzQ5YzFhZTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIKICAgICAgICAgZD0ibSAzMzguMjIzLDY4MC42NzIgYyAtNi40ODksLTMyLjM4MyAtOS44MDksLTY1Ljk4MSAtOS44MDksLTk5Ljk3MyAwLC0yNzYuOTI5IDIyNS4zMzYsLTUwMi4yNTc2IDUwMi4zMTMsLTUwMi4yNTc2IDE2Ni41OTMsMCAzMjEuNDczLDgyLjExNzYgNDE1LjAxMywyMTkuOTQ5NiBsIDczLjk3LDM4NS4zNDcgLTk4LjcyLDE4OC42MjEgTCA3NzUuMTU2LDEwNzUuNTcgMzM4LjIyMyw2ODAuNjcyIiAvPjxwYXRoCiAgICAgICAgIGlkPSJwYXRoMjAiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNlZjI5OWI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiCiAgICAgICAgIGQ9Im0gMzM1LjQxLDE0NDkuMTggMzA0LjMzMiwtNzEuODYgNjYuNjgsMzQ2LjAyIGMgLTQxLjU4NiwzMS43OCAtOTIuOTMsNDkuMTggLTE0NS43MzEsNDkuMTggLTEzMi4yNSwwIC0yMzkuODEyLC0xMDcuNjEgLTIzOS44MTIsLTIzOS44NyAwLC0yOS4yMSA0Ljg3OSwtNTcuMjIgMTQuNTMxLC04My40NyIgLz48cGF0aAogICAgICAgICBpZD0icGF0aDIyIgogICAgICAgICBzdHlsZT0iZmlsbDojNGNhYmU0O2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIgogICAgICAgICBkPSJNIDMwOC45OTIsMTM3Ni43IEMgMTczLjAyLDEzMzEuNjQgNzguNDgwNSwxMjAxLjMgNzguNDgwNSwxMDU3LjkzIDc4LjQ4MDUsOTE4LjM0IDE2NC44Miw3OTMuNjggMjk0LjQwNiw3NDQuMzUyIGwgNDI2Ljk4MSwzODUuOTM4IC03OC4zOTUsMTY3LjUxIC0zMzQsNzguOSIgLz48cGF0aAogICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICBzdHlsZT0iZmlsbDojODVjZTI2O2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIgogICAgICAgICBkPSJtIDEzMjMuOCwyOTguNDEgYyA0MS43NCwtMzIuMDkgOTIuODMsLTQ5LjU5IDE0NC45OCwtNDkuNTkgMTMyLjI1LDAgMjM5LjgxLDEwNy41NTkgMjM5LjgxLDIzOS44MjEgMCwyOS4xNiAtNC44OCw1Ny4xNjggLTE0LjUzLDgzLjQxOCBsIC0zMDQuMDgsNzEuMTYgLTY2LjE4LC0zNDQuODA5IiAvPjxwYXRoCiAgICAgICAgIGlkPSJwYXRoMjYiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMzMTc3YTc7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiCiAgICAgICAgIGQ9Im0gMTM4NS42Nyw3MjIuOTMgMzM0Ljc2LC03OC4zMDEgYyAxMzYuMDIsNDQuOTYxIDIzMC41NiwxNzUuMzUxIDIzMC41NiwzMTguNzYyIDAsMTM5LjMzOSAtODYuNTQsMjYzLjg1OSAtMjE2LjM4LDMxMy4wMzkgbCAtNDM3Ljg0LC0zODMuNTkgODguOSwtMTY5LjkxIiAvPjwvZz48L2c+PC9zdmc+"
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
className="euiCard__content"
|
||||
>
|
||||
<span
|
||||
className="euiTitle euiTitle--medium euiCard__title"
|
||||
id="generated-idTitle"
|
||||
>
|
||||
Image
|
||||
</span>
|
||||
<div
|
||||
className="euiText euiText--small euiCard__description"
|
||||
id="generated-idDescription"
|
||||
>
|
||||
<p>
|
||||
A static image
|
||||
</p>
|
||||
</div>
|
||||
</span>
|
||||
<span
|
||||
className="euiCard__footer"
|
||||
>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
graphic
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/ElementTypes/ElementGrid with text filter 1`] = `
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
|
@ -577,7 +651,27 @@ exports[`Storyshots components/ElementTypes/ElementGrid with filter 1`] = `
|
|||
</span>
|
||||
<span
|
||||
className="euiCard__footer"
|
||||
/>
|
||||
>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
text
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -631,7 +725,27 @@ exports[`Storyshots components/ElementTypes/ElementGrid without controls 1`] = `
|
|||
</span>
|
||||
<span
|
||||
className="euiCard__footer"
|
||||
/>
|
||||
>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
chart
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
|
@ -670,7 +784,27 @@ exports[`Storyshots components/ElementTypes/ElementGrid without controls 1`] = `
|
|||
</span>
|
||||
<span
|
||||
className="euiCard__footer"
|
||||
/>
|
||||
>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
graphic
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
|
@ -709,7 +843,27 @@ exports[`Storyshots components/ElementTypes/ElementGrid without controls 1`] = `
|
|||
</span>
|
||||
<span
|
||||
className="euiCard__footer"
|
||||
/>
|
||||
>
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
text
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -32,14 +32,25 @@ storiesOf('components/ElementTypes/ElementGrid', module)
|
|||
onEdit={action('onEdit')}
|
||||
/>
|
||||
))
|
||||
.add('with filter', () => (
|
||||
<ElementGrid elements={testElements} handleClick={action('addCustomElement')} filter="table" />
|
||||
.add('with text filter', () => (
|
||||
<ElementGrid
|
||||
elements={testElements}
|
||||
handleClick={action('addCustomElement')}
|
||||
filterText="table"
|
||||
/>
|
||||
))
|
||||
.add('with tags filter', () => (
|
||||
<ElementGrid
|
||||
elements={testElements}
|
||||
handleClick={action('addCustomElement')}
|
||||
filterTags={['graphic']}
|
||||
/>
|
||||
))
|
||||
.add('with controls and filter', () => (
|
||||
<ElementGrid
|
||||
elements={testCustomElements}
|
||||
handleClick={action('addCustomElement')}
|
||||
filter="Lorem"
|
||||
filterText="Lorem"
|
||||
showControls
|
||||
onDelete={action('onDelete')}
|
||||
onEdit={action('onEdit')}
|
||||
|
|
|
@ -11,6 +11,7 @@ export const testElements = [
|
|||
name: 'areaChart',
|
||||
displayName: 'Area chart',
|
||||
help: 'A line chart with a filled body',
|
||||
tags: ['chart'],
|
||||
image: elasticLogo,
|
||||
expression: `filters
|
||||
| demodata
|
||||
|
@ -22,6 +23,7 @@ export const testElements = [
|
|||
name: 'image',
|
||||
displayName: 'Image',
|
||||
help: 'A static image',
|
||||
tags: ['graphic'],
|
||||
image: elasticLogo,
|
||||
expression: `image dataurl=null mode="contain"
|
||||
| render`,
|
||||
|
@ -29,6 +31,7 @@ export const testElements = [
|
|||
{
|
||||
name: 'table',
|
||||
displayName: 'Data table',
|
||||
tags: ['text'],
|
||||
help: 'A scrollable grid for displaying data in a tabular format',
|
||||
image: elasticLogo,
|
||||
expression: `filters
|
||||
|
@ -37,6 +40,7 @@ export const testElements = [
|
|||
| render`,
|
||||
},
|
||||
];
|
||||
|
||||
export const testCustomElements = [
|
||||
{
|
||||
id: 'custom-element-10d625f5-1342-47c9-8f19-d174ea6b65d5',
|
||||
|
|
|
@ -18,9 +18,13 @@ export interface Props {
|
|||
*/
|
||||
elements: Array<ElementSpec | CustomElement>;
|
||||
/**
|
||||
* text filter to filter out cards
|
||||
* text to filter out cards
|
||||
*/
|
||||
filter: string;
|
||||
filterText: string;
|
||||
/**
|
||||
* tags to filter out cards
|
||||
*/
|
||||
filterTags: string[];
|
||||
/**
|
||||
* indicate whether or not edit/delete controls should be displayed
|
||||
*/
|
||||
|
@ -41,31 +45,37 @@ export interface Props {
|
|||
|
||||
export const ElementGrid = ({
|
||||
elements,
|
||||
filter,
|
||||
filterText,
|
||||
filterTags,
|
||||
handleClick,
|
||||
onEdit,
|
||||
onDelete,
|
||||
showControls,
|
||||
}: Props) => {
|
||||
filter = filter.toLowerCase();
|
||||
filterText = filterText.toLowerCase();
|
||||
|
||||
return (
|
||||
<EuiFlexGrid gutterSize="l" columns={4}>
|
||||
{map(elements, (element: ElementSpec | CustomElement, index) => {
|
||||
const { help = '', name, displayName = '', image } = element;
|
||||
const { name, displayName = '', help = '', image, tags = [] } = element;
|
||||
const whenClicked = () => handleClick(element);
|
||||
let textMatch = false;
|
||||
let tagsMatch = false;
|
||||
|
||||
if (
|
||||
!filter.length ||
|
||||
name.toLowerCase().includes(filter) ||
|
||||
displayName.toLowerCase().includes(filter) ||
|
||||
help.toLowerCase().includes(filter)
|
||||
!filterText.length ||
|
||||
name.toLowerCase().includes(filterText) ||
|
||||
displayName.toLowerCase().includes(filterText) ||
|
||||
help.toLowerCase().includes(filterText)
|
||||
) {
|
||||
textMatch = true;
|
||||
}
|
||||
|
||||
if (!textMatch) {
|
||||
if (!filterTags.length || filterTags.every(tag => tags.includes(tag))) {
|
||||
tagsMatch = true;
|
||||
}
|
||||
|
||||
if (!textMatch || !tagsMatch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -75,6 +85,7 @@ export const ElementGrid = ({
|
|||
title={displayName || name}
|
||||
description={help}
|
||||
image={image}
|
||||
tags={tags}
|
||||
onClick={whenClicked}
|
||||
/>
|
||||
{showControls && onEdit && onDelete && (
|
||||
|
@ -95,5 +106,6 @@ ElementGrid.propTypes = {
|
|||
|
||||
ElementGrid.defaultProps = {
|
||||
showControls: false,
|
||||
filter: '',
|
||||
filterTags: [],
|
||||
filterText: '',
|
||||
};
|
||||
|
|
|
@ -7,33 +7,35 @@
|
|||
import React, { Component, Fragment } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {
|
||||
EuiFieldSearch,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiModalHeader,
|
||||
EuiModalBody,
|
||||
EuiTabbedContent,
|
||||
EuiEmptyPrompt,
|
||||
EuiSearchBar,
|
||||
EuiSpacer,
|
||||
EuiOverlayMask,
|
||||
} from '@elastic/eui';
|
||||
import { map, sortBy } from 'lodash';
|
||||
import { ConfirmModal } from '../confirm_modal/confirm_modal';
|
||||
import { CustomElementModal } from '../custom_element_modal';
|
||||
import { getTagsFilter } from '../../lib/get_tags_filter';
|
||||
import { extractSearch } from '../../lib/extract_search';
|
||||
import { ElementGrid } from './element_grid';
|
||||
|
||||
const tagType = 'badge';
|
||||
export class ElementTypes extends Component {
|
||||
static propTypes = {
|
||||
addCustomElement: PropTypes.func.isRequired,
|
||||
addElement: PropTypes.func.isRequired,
|
||||
customElements: PropTypes.array.isRequired,
|
||||
elements: PropTypes.object,
|
||||
filterTags: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
findCustomElements: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
removeCustomElement: PropTypes.func.isRequired,
|
||||
search: PropTypes.string,
|
||||
setCustomElements: PropTypes.func.isRequired,
|
||||
setSearch: PropTypes.func.isRequired,
|
||||
setFilterTags: PropTypes.func.isRequired,
|
||||
updateCustomElement: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
@ -113,7 +115,14 @@ export class ElementTypes extends Component {
|
|||
sortBy(map(elements, (element, name) => ({ name, ...element })), 'displayName');
|
||||
|
||||
render() {
|
||||
const { search, setSearch, addElement, addCustomElement } = this.props;
|
||||
const {
|
||||
search,
|
||||
setSearch,
|
||||
addElement,
|
||||
addCustomElement,
|
||||
filterTags,
|
||||
setFilterTags,
|
||||
} = this.props;
|
||||
let { elements, customElements } = this.props;
|
||||
elements = this._sortElements(elements);
|
||||
|
||||
|
@ -140,6 +149,13 @@ export class ElementTypes extends Component {
|
|||
);
|
||||
}
|
||||
|
||||
const filters = [getTagsFilter(tagType)];
|
||||
const onSearch = ({ queryText }) => {
|
||||
const { searchTerm, filterTags } = extractSearch(queryText);
|
||||
setSearch(searchTerm);
|
||||
setFilterTags(filterTags);
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{
|
||||
id: 'elements',
|
||||
|
@ -147,7 +163,22 @@ export class ElementTypes extends Component {
|
|||
content: (
|
||||
<Fragment>
|
||||
<EuiSpacer />
|
||||
<ElementGrid elements={elements} filter={search} handleClick={addElement} />
|
||||
<EuiSearchBar
|
||||
defaultQuery={search}
|
||||
box={{
|
||||
placeholder: 'Find element',
|
||||
incremental: true,
|
||||
}}
|
||||
filters={filters}
|
||||
onChange={onSearch}
|
||||
/>
|
||||
<EuiSpacer />
|
||||
<ElementGrid
|
||||
elements={elements}
|
||||
filterText={search}
|
||||
filterTags={filterTags}
|
||||
handleClick={addElement}
|
||||
/>
|
||||
</Fragment>
|
||||
),
|
||||
},
|
||||
|
@ -156,6 +187,15 @@ export class ElementTypes extends Component {
|
|||
name: 'My elements',
|
||||
content: (
|
||||
<Fragment>
|
||||
<EuiSpacer />
|
||||
<EuiSearchBar
|
||||
defaultQuery={search}
|
||||
box={{
|
||||
placeholder: 'Find element',
|
||||
incremental: true,
|
||||
}}
|
||||
onChange={onSearch}
|
||||
/>
|
||||
<EuiSpacer />
|
||||
{customElementContent}
|
||||
</Fragment>
|
||||
|
@ -165,19 +205,7 @@ export class ElementTypes extends Component {
|
|||
|
||||
return (
|
||||
<Fragment>
|
||||
<EuiModalHeader>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFieldSearch
|
||||
className="canvasElements__filter"
|
||||
placeholder="Filter elements"
|
||||
onChange={e => setSearch(e.target.value)}
|
||||
value={search}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiModalHeader>
|
||||
<EuiModalBody>
|
||||
<EuiModalBody style={{ paddingRight: '1px' }}>
|
||||
<EuiTabbedContent tabs={tabs} initialSelectedTab={tabs[0]} />
|
||||
</EuiModalBody>
|
||||
|
||||
|
|
|
@ -17,10 +17,6 @@ import { insertNodes, addElement } from '../../state/actions/elements';
|
|||
import { getSelectedPage } from '../../state/selectors/workpad';
|
||||
import { ElementTypes as Component } from './element_types';
|
||||
|
||||
const elementTypesState = withState('search', 'setSearch', '');
|
||||
const customElementsState = withState('customElements', 'setCustomElements', []);
|
||||
const elementTypeProps = withProps(() => ({ elements: elementsRegistry.toJS() }));
|
||||
|
||||
const mapStateToProps = state => ({ pageId: getSelectedPage(state) });
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
|
@ -91,9 +87,10 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
|||
};
|
||||
|
||||
export const ElementTypes = compose(
|
||||
elementTypesState,
|
||||
elementTypeProps,
|
||||
customElementsState,
|
||||
withState('search', 'setSearch', ''),
|
||||
withState('customElements', 'setCustomElements', []),
|
||||
withState('filterTags', 'setFilterTags', []),
|
||||
withProps(() => ({ elements: elementsRegistry.toJS() })),
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
|
|
137
x-pack/plugins/canvas/public/components/tag/__examples__/__snapshots__/tag.examples.storyshot
generated
Normal file
137
x-pack/plugins/canvas/public/components/tag/__examples__/__snapshots__/tag.examples.storyshot
generated
Normal file
|
@ -0,0 +1,137 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots components/Tag as badge 1`] = `
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#666666",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/Tag as badge with color 1`] = `
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#327b53",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/Tag as health 1`] = `
|
||||
<div
|
||||
className="euiHealth"
|
||||
>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterExtraSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<svg
|
||||
className="euiIcon euiIcon--medium"
|
||||
focusable="false"
|
||||
height="16"
|
||||
style={
|
||||
Object {
|
||||
"fill": "#666666",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<defs>
|
||||
<circle
|
||||
cx="8"
|
||||
cy="8"
|
||||
id="dot-a"
|
||||
r="4"
|
||||
/>
|
||||
</defs>
|
||||
<use
|
||||
xlinkHref="#dot-a"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
tag
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/Tag as health with color 1`] = `
|
||||
<div
|
||||
className="euiHealth"
|
||||
>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterExtraSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<svg
|
||||
className="euiIcon euiIcon--medium"
|
||||
focusable="false"
|
||||
height="16"
|
||||
style={
|
||||
Object {
|
||||
"fill": "#9b3067",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<defs>
|
||||
<circle
|
||||
cx="8"
|
||||
cy="8"
|
||||
id="dot-a"
|
||||
r="4"
|
||||
/>
|
||||
</defs>
|
||||
<use
|
||||
xlinkHref="#dot-a"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
tag
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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 { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { Tag } from '../tag';
|
||||
|
||||
storiesOf('components/Tag', module)
|
||||
.add('as health', () => <Tag name="tag" />)
|
||||
.add('as health with color', () => <Tag name="tag" color="#9b3067" />)
|
||||
.add('as badge', () => <Tag name="tag" type="badge" />)
|
||||
.add('as badge with color', () => <Tag name="tag" type="badge" color="#327b53" />);
|
|
@ -4,4 +4,4 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const report = () => ({ name: 'report', color: '#DB1374' });
|
||||
export { Tag } from './tag';
|
52
x-pack/plugins/canvas/public/components/tag/tag.tsx
Normal file
52
x-pack/plugins/canvas/public/components/tag/tag.tsx
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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, { FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { EuiBadge, EuiHealth } from '@elastic/eui';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* name of the tag
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* color of the tag
|
||||
*/
|
||||
color?: string;
|
||||
/**
|
||||
* type of tag to display, i.e. EuiHealth or EuiBadge
|
||||
*/
|
||||
type?: 'health' | 'badge';
|
||||
}
|
||||
|
||||
export const Tag: FunctionComponent<Props> = ({
|
||||
name,
|
||||
color = '#666666',
|
||||
type = 'health',
|
||||
...rest
|
||||
}) => {
|
||||
switch (type) {
|
||||
case 'health':
|
||||
return (
|
||||
<EuiHealth color={color} {...rest}>
|
||||
{name}
|
||||
</EuiHealth>
|
||||
);
|
||||
case 'badge':
|
||||
return (
|
||||
<EuiBadge color={color} {...rest}>
|
||||
{name}
|
||||
</EuiBadge>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
Tag.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
color: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
};
|
394
x-pack/plugins/canvas/public/components/tag_list/__examples__/__snapshots__/tag_list.examples.storyshot
generated
Normal file
394
x-pack/plugins/canvas/public/components/tag_list/__examples__/__snapshots__/tag_list.examples.storyshot
generated
Normal file
|
@ -0,0 +1,394 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Storyshots components/TagList empty list 1`] = `null`;
|
||||
|
||||
exports[`Storyshots components/TagList with badge tags 1`] = `
|
||||
Array [
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#cc3b54",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag1
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#5bc149",
|
||||
"color": "#000000",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag2
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#fbc545",
|
||||
"color": "#000000",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag3
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/TagList with health tags 1`] = `
|
||||
Array [
|
||||
<div
|
||||
className="euiHealth"
|
||||
>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterExtraSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<svg
|
||||
className="euiIcon euiIcon--medium"
|
||||
focusable="false"
|
||||
height="16"
|
||||
style={
|
||||
Object {
|
||||
"fill": "#cc3b54",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<defs>
|
||||
<circle
|
||||
cx="8"
|
||||
cy="8"
|
||||
id="dot-a"
|
||||
r="4"
|
||||
/>
|
||||
</defs>
|
||||
<use
|
||||
xlinkHref="#dot-a"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
tag1
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
className="euiHealth"
|
||||
>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterExtraSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<svg
|
||||
className="euiIcon euiIcon--medium"
|
||||
focusable="false"
|
||||
height="16"
|
||||
style={
|
||||
Object {
|
||||
"fill": "#9b3067",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<defs>
|
||||
<circle
|
||||
cx="8"
|
||||
cy="8"
|
||||
id="dot-a"
|
||||
r="4"
|
||||
/>
|
||||
</defs>
|
||||
<use
|
||||
xlinkHref="#dot-a"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
tag4
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
<div
|
||||
className="euiHealth"
|
||||
>
|
||||
<div
|
||||
className="euiFlexGroup euiFlexGroup--gutterExtraSmall euiFlexGroup--alignItemsCenter euiFlexGroup--directionRow"
|
||||
>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
<svg
|
||||
className="euiIcon euiIcon--medium"
|
||||
focusable="false"
|
||||
height="16"
|
||||
style={
|
||||
Object {
|
||||
"fill": "#d41e93",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
>
|
||||
<defs>
|
||||
<circle
|
||||
cx="8"
|
||||
cy="8"
|
||||
id="dot-a"
|
||||
r="4"
|
||||
/>
|
||||
</defs>
|
||||
<use
|
||||
xlinkHref="#dot-a"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
className="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
>
|
||||
tag6
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Storyshots components/TagList with lots of tags 1`] = `
|
||||
Array [
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#cc3b54",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag1
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#5bc149",
|
||||
"color": "#000000",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag2
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#fbc545",
|
||||
"color": "#000000",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag3
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#9b3067",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag4
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#1819bd",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag5
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#d41e93",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag6
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#3486d2",
|
||||
"color": "#000000",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag7
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#b870d8",
|
||||
"color": "#000000",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag8
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#f4a4a7",
|
||||
"color": "#000000",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag9
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<span
|
||||
className="euiBadge"
|
||||
style={
|
||||
Object {
|
||||
"backgroundColor": "#072d6d",
|
||||
"color": "#FFFFFF",
|
||||
}
|
||||
}
|
||||
>
|
||||
<span
|
||||
className="euiBadge__content"
|
||||
>
|
||||
<span
|
||||
className="euiBadge__text"
|
||||
>
|
||||
tag10
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
]
|
||||
`;
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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 { storiesOf } from '@storybook/react';
|
||||
import React from 'react';
|
||||
import { TagList } from '../tag_list';
|
||||
import { TagSpec } from '../../../lib/tag';
|
||||
|
||||
const mockTagRegistry: { [tag: string]: TagSpec } = {
|
||||
tag1: {
|
||||
name: 'tag1',
|
||||
color: '#cc3b54',
|
||||
},
|
||||
tag2: {
|
||||
name: 'tag2',
|
||||
color: '#5bc149',
|
||||
},
|
||||
tag3: {
|
||||
name: 'tag3',
|
||||
color: '#fbc545',
|
||||
},
|
||||
tag4: {
|
||||
name: 'tag4',
|
||||
color: '#9b3067',
|
||||
},
|
||||
tag5: {
|
||||
name: 'tag5',
|
||||
color: '#1819bd',
|
||||
},
|
||||
tag6: {
|
||||
name: 'tag6',
|
||||
color: '#d41e93',
|
||||
},
|
||||
tag7: {
|
||||
name: 'tag7',
|
||||
color: '#3486d2',
|
||||
},
|
||||
tag8: {
|
||||
name: 'tag8',
|
||||
color: '#b870d8',
|
||||
},
|
||||
tag9: {
|
||||
name: 'tag9',
|
||||
color: '#f4a4a7',
|
||||
},
|
||||
tag10: {
|
||||
name: 'tag10',
|
||||
color: '#072d6d',
|
||||
},
|
||||
};
|
||||
|
||||
const getTag = (name: string): TagSpec => mockTagRegistry[name] || { name, color: '#666666' };
|
||||
|
||||
storiesOf('components/TagList', module)
|
||||
.add('empty list', () => <TagList getTag={getTag} />)
|
||||
.add('with health tags', () => <TagList tags={['tag1', 'tag4', 'tag6']} getTag={getTag} />)
|
||||
.add('with badge tags', () => (
|
||||
<TagList tags={['tag1', 'tag2', 'tag3']} getTag={getTag} tagType="badge" />
|
||||
))
|
||||
.add('with lots of tags', () => (
|
||||
<TagList
|
||||
tags={['tag1', 'tag2', 'tag3', 'tag4', 'tag5', 'tag6', 'tag7', 'tag8', 'tag9', 'tag10']}
|
||||
getTag={getTag}
|
||||
tagType="badge"
|
||||
/>
|
||||
));
|
27
x-pack/plugins/canvas/public/components/tag_list/index.tsx
Normal file
27
x-pack/plugins/canvas/public/components/tag_list/index.tsx
Normal file
|
@ -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 { compose, withProps } from 'recompose';
|
||||
import { tagsRegistry } from '../../lib/tags_registry';
|
||||
import { TagList as Component, Props as ComponentProps } from './tag_list';
|
||||
import { TagSpec } from '../../lib/tag';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* list of tags to display in the list
|
||||
*/
|
||||
tags: string[];
|
||||
/**
|
||||
* choose EuiHealth or EuiBadge
|
||||
*/
|
||||
tagType: 'health' | 'badge';
|
||||
}
|
||||
|
||||
export const TagList = compose<ComponentProps, Props>(
|
||||
withProps(() => ({
|
||||
getTag: (tag: string): TagSpec => tagsRegistry.get(tag) || { name: tag, color: undefined },
|
||||
}))
|
||||
)(Component);
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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, { Fragment, FunctionComponent } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getId } from '../../lib/get_id';
|
||||
import { Tag } from '../tag';
|
||||
import { TagSpec } from '../../lib/tag';
|
||||
|
||||
export interface Props {
|
||||
/**
|
||||
* list of tags to display in the list
|
||||
*/
|
||||
tags?: string[];
|
||||
/**
|
||||
* choose EuiHealth or EuiBadge
|
||||
*/
|
||||
tagType?: 'health' | 'badge';
|
||||
/**
|
||||
* gets the tag from the tag registry
|
||||
*/
|
||||
getTag: (tagName: string) => TagSpec;
|
||||
}
|
||||
|
||||
export const TagList: FunctionComponent<Props> = ({ tags = [], tagType = 'health', getTag }) => (
|
||||
<Fragment>
|
||||
{tags.length
|
||||
? tags.map((tag: string) => {
|
||||
const { color, name } = getTag(tag);
|
||||
const id = getId('tag');
|
||||
return <Tag key={id} color={color} name={name} type={tagType} />;
|
||||
})
|
||||
: null}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
TagList.propTypes = {
|
||||
tags: PropTypes.array,
|
||||
tagType: PropTypes.oneOf(['health', 'badge']),
|
||||
getTag: PropTypes.func.isRequired,
|
||||
};
|
|
@ -57,7 +57,7 @@ export class WorkpadHeader extends React.PureComponent {
|
|||
onClose={this._hideElementModal}
|
||||
className="canvasModal--fixedSize"
|
||||
maxWidth="1000px"
|
||||
initialFocus=".canvasElements__filter"
|
||||
initialFocus=".canvasElements__filter input"
|
||||
>
|
||||
<ElementTypes onClose={this._hideElementModal} />
|
||||
<EuiModalFooter>
|
||||
|
|
|
@ -10,7 +10,6 @@ import * as workpadService from '../../lib/workpad_service';
|
|||
import { notify } from '../../lib/notify';
|
||||
import { getId } from '../../lib/get_id';
|
||||
import { templatesRegistry } from '../../lib/templates_registry';
|
||||
import { tagsRegistry } from '../../lib/tags_registry';
|
||||
import { WorkpadTemplates as Component } from './workpad_templates';
|
||||
|
||||
export const WorkpadTemplates = compose(
|
||||
|
@ -19,7 +18,6 @@ export const WorkpadTemplates = compose(
|
|||
}),
|
||||
withProps(() => ({
|
||||
templates: templatesRegistry.toJS(),
|
||||
uniqueTags: tagsRegistry.toJS(),
|
||||
})),
|
||||
withHandlers({
|
||||
// Clone workpad given an id
|
||||
|
|
|
@ -12,13 +12,14 @@ import {
|
|||
EuiBasicTable,
|
||||
EuiPagination,
|
||||
EuiSpacer,
|
||||
EuiHealth,
|
||||
EuiButtonEmpty,
|
||||
EuiSearchBar,
|
||||
} from '@elastic/eui';
|
||||
import { get, sortByOrder } from 'lodash';
|
||||
import { getId } from '../../lib/get_id';
|
||||
import { sortByOrder } from 'lodash';
|
||||
import { Paginate } from '../paginate';
|
||||
import { TagList } from '../tag_list';
|
||||
import { getTagsFilter } from '../../lib/get_tags_filter';
|
||||
import { extractSearch } from '../../lib/extract_search';
|
||||
|
||||
export class WorkpadTemplates extends React.PureComponent {
|
||||
static propTypes = {
|
||||
|
@ -35,6 +36,8 @@ export class WorkpadTemplates extends React.PureComponent {
|
|||
filterTags: [],
|
||||
};
|
||||
|
||||
tagType = 'health';
|
||||
|
||||
onTableChange = ({ sort = {} }) => {
|
||||
const { field: sortField, direction: sortDirection } = sort;
|
||||
this.setState({
|
||||
|
@ -43,31 +46,11 @@ export class WorkpadTemplates extends React.PureComponent {
|
|||
});
|
||||
};
|
||||
|
||||
onSearch = ({ query }) => {
|
||||
const clauses = get(query, 'ast._clauses', []);
|
||||
|
||||
const filterTags = [];
|
||||
const searchTerms = [];
|
||||
|
||||
clauses.forEach(clause => {
|
||||
const { type, field, value } = clause;
|
||||
// extract terms from the query AST
|
||||
if (type === 'term') {
|
||||
searchTerms.push(value);
|
||||
}
|
||||
// extracts tags from the query AST
|
||||
else if (field === 'tags') {
|
||||
filterTags.push(value);
|
||||
}
|
||||
});
|
||||
|
||||
this.setState({ searchTerm: searchTerms.join(' '), filterTags });
|
||||
};
|
||||
onSearch = ({ queryText }) => this.setState(extractSearch(queryText));
|
||||
|
||||
cloneTemplate = template => this.props.cloneWorkpad(template).then(() => this.props.onClose());
|
||||
|
||||
renderWorkpadTable = ({ rows, pageNumber, totalPages, setPage }) => {
|
||||
const { uniqueTags } = this.props;
|
||||
const { sortField, sortDirection } = this.state;
|
||||
|
||||
const columns = [
|
||||
|
@ -104,16 +87,7 @@ export class WorkpadTemplates extends React.PureComponent {
|
|||
sortable: false,
|
||||
dataType: 'string',
|
||||
width: '30%',
|
||||
render: tags => {
|
||||
if (!tags) {
|
||||
return 'No tags';
|
||||
}
|
||||
return tags.map(tag => (
|
||||
<EuiHealth key={getId('tag')} color={get(uniqueTags, `${tag}.color`, '#666666')}>
|
||||
{tag}
|
||||
</EuiHealth>
|
||||
));
|
||||
},
|
||||
render: tags => <TagList tags={tags} tagType={this.tagType} />,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -146,28 +120,8 @@ export class WorkpadTemplates extends React.PureComponent {
|
|||
};
|
||||
|
||||
renderSearch = () => {
|
||||
let { uniqueTags } = this.props;
|
||||
const { searchTerm } = this.state;
|
||||
|
||||
uniqueTags = Object.values(uniqueTags);
|
||||
|
||||
const filters = [
|
||||
{
|
||||
type: 'field_value_selection',
|
||||
field: 'tags',
|
||||
name: 'Tags',
|
||||
multiSelect: true,
|
||||
options: uniqueTags.map(({ name, color }) => ({
|
||||
value: name,
|
||||
name: name,
|
||||
view: (
|
||||
<EuiHealth key={getId('tag')} color={color}>
|
||||
{name}
|
||||
</EuiHealth>
|
||||
),
|
||||
})),
|
||||
},
|
||||
];
|
||||
const filters = [getTagsFilter(this.tagType)];
|
||||
|
||||
return (
|
||||
<EuiSearchBar
|
||||
|
|
|
@ -25,6 +25,10 @@ export interface CustomElement {
|
|||
* base 64 data URL string of the preview image
|
||||
*/
|
||||
image?: string;
|
||||
/**
|
||||
* tags associated with the element
|
||||
*/
|
||||
tags?: string[];
|
||||
/**
|
||||
* the element object stringified
|
||||
*/
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
|
||||
import { ElementSpec } from '../../canvas_plugin_src/elements/types';
|
||||
import defaultHeader from './default_header.png';
|
||||
import { tagsRegistry } from './tags_registry';
|
||||
|
||||
export class Element {
|
||||
/** The name of the Element. This must match the name of the function that is used to create the `type: render` object */
|
||||
public name: string;
|
||||
/** A more friendly name for the Element */
|
||||
public displayName: string;
|
||||
/** Relevant labels to help identify the elements */
|
||||
public tags: string[];
|
||||
/** An image to use in the Element type selector */
|
||||
public image: string;
|
||||
/** A sentence or few about what this Element does */
|
||||
|
@ -25,7 +28,7 @@ export class Element {
|
|||
public height?: number;
|
||||
|
||||
constructor(config: ElementSpec) {
|
||||
const { name, image, displayName, expression, filter, help, width, height } = config;
|
||||
const { name, image, displayName, tags, expression, filter, help, width, height } = config;
|
||||
this.name = name;
|
||||
this.displayName = displayName || name;
|
||||
this.image = image || defaultHeader;
|
||||
|
@ -35,6 +38,13 @@ export class Element {
|
|||
throw new Error('Element types must have a default expression');
|
||||
}
|
||||
|
||||
this.tags = tags || [];
|
||||
|
||||
this.tags.forEach(tag => {
|
||||
if (!tagsRegistry.get(tag)) {
|
||||
tagsRegistry.register(() => ({ name: tag, color: '#666666' }));
|
||||
}
|
||||
});
|
||||
this.expression = expression;
|
||||
this.filter = filter;
|
||||
this.width = width || 500;
|
||||
|
|
27
x-pack/plugins/canvas/public/lib/extract_search.js
Normal file
27
x-pack/plugins/canvas/public/lib/extract_search.js
Normal file
|
@ -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.
|
||||
*/
|
||||
|
||||
// EUI helper
|
||||
// extracts search text and array of selected tags from EuiSearchBar
|
||||
export const extractSearch = queryText => {
|
||||
const filterTags = [];
|
||||
const searchTerms = [];
|
||||
const parts = queryText.split(' ');
|
||||
|
||||
parts.forEach(part => {
|
||||
if (part.indexOf(':') >= 0) {
|
||||
const [key, value] = part.split(':');
|
||||
if (key === 'tag') {
|
||||
filterTags.push(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
searchTerms.push(part);
|
||||
});
|
||||
|
||||
return { searchTerm: searchTerms.join(' '), filterTags };
|
||||
};
|
33
x-pack/plugins/canvas/public/lib/get_tags_filter.tsx
Normal file
33
x-pack/plugins/canvas/public/lib/get_tags_filter.tsx
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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 { sortBy } from 'lodash';
|
||||
import { Tag } from '../components/tag';
|
||||
import { getId } from './get_id';
|
||||
import { tagsRegistry } from './tags_registry';
|
||||
|
||||
// EUI helper function
|
||||
// generates the FieldValueSelectionFilter object for EuiSearchBar for tag filtering
|
||||
export const getTagsFilter = (type: 'health' | 'badge') => {
|
||||
const uniqueTags = sortBy(Object.values(tagsRegistry.toJS()), 'name');
|
||||
|
||||
return {
|
||||
type: 'field_value_selection',
|
||||
field: 'tag',
|
||||
name: 'Tags',
|
||||
multiSelect: true,
|
||||
options: uniqueTags.map(({ name, color }) => ({
|
||||
value: name,
|
||||
name,
|
||||
view: (
|
||||
<div>
|
||||
<Tag key={getId('tag')} color={color} name={name} type={type} />
|
||||
</div>
|
||||
),
|
||||
})),
|
||||
};
|
||||
};
|
27
x-pack/plugins/canvas/public/lib/tag.ts
Normal file
27
x-pack/plugins/canvas/public/lib/tag.ts
Normal file
|
@ -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.
|
||||
*/
|
||||
|
||||
export interface TagSpec {
|
||||
/**
|
||||
* name of the tag
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* color of the tag
|
||||
*/
|
||||
color: string;
|
||||
}
|
||||
export class Tag implements TagSpec {
|
||||
public name: string;
|
||||
public color: string;
|
||||
|
||||
constructor(config: TagSpec) {
|
||||
this.name = config.name;
|
||||
this.color = config.color;
|
||||
}
|
||||
}
|
||||
|
||||
export type TagFactory = () => TagSpec;
|
|
@ -5,10 +5,10 @@
|
|||
*/
|
||||
|
||||
import { Registry } from '@kbn/interpreter/common';
|
||||
import { Tag } from './tag';
|
||||
import { Tag, TagSpec } from './tag';
|
||||
|
||||
class TagRegistry extends Registry {
|
||||
wrapper(obj) {
|
||||
class TagRegistry extends Registry<TagSpec, Tag> {
|
||||
public wrapper(obj: TagSpec) {
|
||||
return new Tag(obj);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue