diff --git a/package.json b/package.json index 90d05f9c7be..cc55d3cedc3 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "prop-types": "^15.6.0", "react-beautiful-dnd": "^13.1.0", "react-dropzone": "^11.5.3", + "react-element-to-jsx-string": "^14.3.4", "react-focus-on": "^3.5.4", "react-input-autosize": "^3.0.0", "react-is": "^17.0.2", diff --git a/scripts/babel/proptypes-from-ts-props/index.js b/scripts/babel/proptypes-from-ts-props/index.js index 5ee71b02c59..2af5e0b24b8 100644 --- a/scripts/babel/proptypes-from-ts-props/index.js +++ b/scripts/babel/proptypes-from-ts-props/index.js @@ -1035,6 +1035,8 @@ function getPropTypesForNode(node, optional, state) { return propType; } +const typescriptExtensions = new Set(['', '.ts', '.tsx']); + // typeDefinitionExtractors is a mapping of [ast_node_type: func] which is used to find type definitions // these definitions come from four sources: // - import statements @@ -1054,9 +1056,11 @@ const typeDefinitionExtractors = { const { fs, sourceFilename, parse, state } = extractionOptions; const importPath = node.source.value; const isPathRelative = /^\.{1,2}\//.test(importPath); + const pathExtension = path.extname(importPath); + const isImportTypecript = typescriptExtensions.has(pathExtension); // only process relative imports for typescript definitions (avoid node_modules) - if (isPathRelative) { + if (isPathRelative && isImportTypecript) { // find the variable names being imported const importedTypeNames = node.specifiers.map(specifier => { switch (specifier.type) { diff --git a/scripts/babel/proptypes-from-ts-props/index.test.ts b/scripts/babel/proptypes-from-ts-props/index.test.ts index 9a96aca23ee..3d519e69409 100644 --- a/scripts/babel/proptypes-from-ts-props/index.test.ts +++ b/scripts/babel/proptypes-from-ts-props/index.test.ts @@ -2514,6 +2514,35 @@ let something: any; expect(result.code).toBe('let something;'); }); + + it('skips non-typescript imports', () => { + const result = transform( + ` +import something from './somewhere.txt'; +`, + { + ...babelOptions, + plugins: [ + [ + './scripts/babel/proptypes-from-ts-props', + { + fs: { + existsSync: () => true, + statSync: () => ({ isDirectory: () => false }), + readFileSync: () => { + return Buffer.from(` + this is not valid javascript + `); + }, + }, + }, + ], + ], + } + ); + + expect(result.code).toBe("export {};"); + }); }); }); }); diff --git a/src-docs/src/components/guide_section/guide_section.tsx b/src-docs/src/components/guide_section/guide_section.tsx index 755eca9a737..873ebfd8d92 100644 --- a/src-docs/src/components/guide_section/guide_section.tsx +++ b/src-docs/src/components/guide_section/guide_section.tsx @@ -48,6 +48,10 @@ export const GuideSectionCodeTypesMap = { name: 'demoTSX', displayName: 'Demo TS', }, + STRING_JS: { + name: 'demoJS', + displayName: 'Demo JS', + }, SNIPPET: { name: 'snippet', displayName: 'Snippet', diff --git a/src-docs/src/components/guide_section/guide_section_parts/guide_section_code.tsx b/src-docs/src/components/guide_section/guide_section_parts/guide_section_code.tsx index c93bfa5c512..a85e3dc0f7b 100644 --- a/src-docs/src/components/guide_section/guide_section_parts/guide_section_code.tsx +++ b/src-docs/src/components/guide_section/guide_section_parts/guide_section_code.tsx @@ -50,7 +50,11 @@ export const GuideSectionExampleCode: FunctionComponent return ( <> diff --git a/src-docs/src/components/guide_section/guide_section_types.tsx b/src-docs/src/components/guide_section/guide_section_types.tsx index 0597b72af2a..e49f40c582e 100644 --- a/src-docs/src/components/guide_section/guide_section_types.tsx +++ b/src-docs/src/components/guide_section/guide_section_types.tsx @@ -3,4 +3,5 @@ export const GuideSectionTypes = { TSX: 'TSX', SNIPPET: 'SNIPPET', SASS: 'SASS', + STRING_JS: 'STRING_JS', }; diff --git a/src-docs/src/images/empty-prompt/404_rainy_cloud_dark.png b/src-docs/src/images/empty-prompt/404_rainy_cloud_dark.png new file mode 100644 index 00000000000..92ca7064fbb Binary files /dev/null and b/src-docs/src/images/empty-prompt/404_rainy_cloud_dark.png differ diff --git a/src-docs/src/images/empty-prompt/404_rainy_cloud_light.png b/src-docs/src/images/empty-prompt/404_rainy_cloud_light.png new file mode 100644 index 00000000000..9735dc6f757 Binary files /dev/null and b/src-docs/src/images/empty-prompt/404_rainy_cloud_light.png differ diff --git a/src-docs/src/images/empty-prompt_illustration.svg b/src-docs/src/images/empty-prompt/illustration.svg similarity index 100% rename from src-docs/src/images/empty-prompt_illustration.svg rename to src-docs/src/images/empty-prompt/illustration.svg diff --git a/src-docs/src/images/empty-prompt/inline-link.svg b/src-docs/src/images/empty-prompt/inline-link.svg new file mode 100644 index 00000000000..b97e81568a2 --- /dev/null +++ b/src-docs/src/images/empty-prompt/inline-link.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/no-results--dark.svg b/src-docs/src/images/empty-prompt/no-results--dark.svg new file mode 100644 index 00000000000..e76cfc10272 --- /dev/null +++ b/src-docs/src/images/empty-prompt/no-results--dark.svg @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/no-results--light.svg b/src-docs/src/images/empty-prompt/no-results--light.svg new file mode 100644 index 00000000000..a2546872380 --- /dev/null +++ b/src-docs/src/images/empty-prompt/no-results--light.svg @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_dark_empty_content.svg b/src-docs/src/images/empty-prompt/thumbnail_dark_empty_content.svg new file mode 100644 index 00000000000..12cd8cc3c78 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_dark_empty_content.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_dark_page-empty.svg b/src-docs/src/images/empty-prompt/thumbnail_dark_page-empty.svg new file mode 100644 index 00000000000..b8d0938d3ea --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_dark_page-empty.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_dark_page-multiple.svg b/src-docs/src/images/empty-prompt/thumbnail_dark_page-multiple.svg new file mode 100644 index 00000000000..9b8b3daf1eb --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_dark_page-multiple.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_dark_page-sidebar.svg b/src-docs/src/images/empty-prompt/thumbnail_dark_page-sidebar.svg new file mode 100644 index 00000000000..e95232cbc81 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_dark_page-sidebar.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_footer-link.svg b/src-docs/src/images/empty-prompt/thumbnail_footer-link.svg new file mode 100644 index 00000000000..a5ab9b08b17 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_footer-link.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_horizontal.svg b/src-docs/src/images/empty-prompt/thumbnail_horizontal.svg new file mode 100644 index 00000000000..ffb40fe5581 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_horizontal.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_icon-do.svg b/src-docs/src/images/empty-prompt/thumbnail_icon-do.svg new file mode 100644 index 00000000000..3c69daa0cad --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_icon-do.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_icon-dont.svg b/src-docs/src/images/empty-prompt/thumbnail_icon-dont.svg new file mode 100644 index 00000000000..6301ae00261 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_icon-dont.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_illustration.svg b/src-docs/src/images/empty-prompt/thumbnail_illustration.svg new file mode 100644 index 00000000000..7f61ef8bea3 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_illustration.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_inline-link.svg b/src-docs/src/images/empty-prompt/thumbnail_inline-link.svg new file mode 100644 index 00000000000..b6f0eb72f4a --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_inline-link.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_light_empty_content.svg b/src-docs/src/images/empty-prompt/thumbnail_light_empty_content.svg new file mode 100644 index 00000000000..0ac477bc5c0 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_light_empty_content.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_light_page-empty.svg b/src-docs/src/images/empty-prompt/thumbnail_light_page-empty.svg new file mode 100644 index 00000000000..4a5fc21496e --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_light_page-empty.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_light_page-multiple.svg b/src-docs/src/images/empty-prompt/thumbnail_light_page-multiple.svg new file mode 100644 index 00000000000..b88215ff5cf --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_light_page-multiple.svg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_light_page-sidebar.svg b/src-docs/src/images/empty-prompt/thumbnail_light_page-sidebar.svg new file mode 100644 index 00000000000..eecf7c40535 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_light_page-sidebar.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_multiple-do.svg b/src-docs/src/images/empty-prompt/thumbnail_multiple-do.svg new file mode 100644 index 00000000000..14cd1a401c2 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_multiple-do.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_multiple-dont.svg b/src-docs/src/images/empty-prompt/thumbnail_multiple-dont.svg new file mode 100644 index 00000000000..2e7f084d816 --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_multiple-dont.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/thumbnail_vertical.svg b/src-docs/src/images/empty-prompt/thumbnail_vertical.svg new file mode 100644 index 00000000000..48e8606bb8a --- /dev/null +++ b/src-docs/src/images/empty-prompt/thumbnail_vertical.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt/vertical.svg b/src-docs/src/images/empty-prompt/vertical.svg new file mode 100644 index 00000000000..75dbf9dbf18 --- /dev/null +++ b/src-docs/src/images/empty-prompt/vertical.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src-docs/src/images/empty-prompt_anatomy.svg b/src-docs/src/images/empty-prompt_anatomy.svg deleted file mode 100644 index 28a0bb62eb4..00000000000 --- a/src-docs/src/images/empty-prompt_anatomy.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src-docs/src/views/_index.scss b/src-docs/src/views/_index.scss index 2537fd6566c..57cb58195e3 100644 --- a/src-docs/src/views/_index.scss +++ b/src-docs/src/views/_index.scss @@ -6,6 +6,7 @@ $guideDemoHighlightColor: transparentize($euiColorPrimary, .9); @import './datagrid/datagrid'; @import './date_picker/date_picker'; @import './elastic_charts/index'; +@import './empty_prompt/empty_prompt'; @import './flex/flex'; @import './horizontal_rule/horizontal_rule'; @import './page/page'; diff --git a/src-docs/src/views/empty_prompt/_empty_prompt.scss b/src-docs/src/views/empty_prompt/_empty_prompt.scss new file mode 100644 index 00000000000..c89e4026a58 --- /dev/null +++ b/src-docs/src/views/empty_prompt/_empty_prompt.scss @@ -0,0 +1,29 @@ +.guideDemo__emptyPromptPanelPicker { + width: 100%; + gap: $euiSizeXL; // sass-lint:disable-line no-misspelled-properties +} + +.guideDemo__emptyPromptPanelPickerThumbBtn { + width: 120px; + height: auto; + + .euiKeyPadMenuItem__icon { + transform: none; + margin-bottom: $euiSizeS; + } +} + +.guideDemo__emptyPromptPanelPickerThumb { + border: $euiBorderThin; + border-radius: $euiBorderRadius; + overflow: hidden; + + &-isSelected { + border-color: $euiColorPrimary; + } +} + +.guideDemo__emptyPromptDemoPreview { + border: 1px solid $guideDemoHighlightColor; + overflow: hidden; +} \ No newline at end of file diff --git a/src-docs/src/views/empty_prompt/_page_template_table.tsx b/src-docs/src/views/empty_prompt/_page_template_table.tsx index 0df2c03957f..8deb150f2ba 100644 --- a/src-docs/src/views/empty_prompt/_page_template_table.tsx +++ b/src-docs/src/views/empty_prompt/_page_template_table.tsx @@ -25,8 +25,7 @@ export default () => ( - Set {'color="plain"'} and - {'hasBorder={true}'}. + Set {'color="subdued"'}. diff --git a/src-docs/src/views/empty_prompt/_types_of_empty_states.tsx b/src-docs/src/views/empty_prompt/_types_of_empty_states.tsx new file mode 100644 index 00000000000..812086cac89 --- /dev/null +++ b/src-docs/src/views/empty_prompt/_types_of_empty_states.tsx @@ -0,0 +1,399 @@ +import React, { useState, useEffect, useContext } from 'react'; +import reactElementToJSXString from 'react-element-to-jsx-string'; +import classNames from 'classnames'; +import { + EuiTitle, + EuiImage, + EuiSpacer, + EuiRadioGroup, + EuiEmptyPrompt, + EuiSplitPanel, + EuiKeyPadMenu, + EuiFlexItem, + EuiRadioGroupOption, + EuiPageTemplate, + EuiFlexGrid, + EuiPanel, + EuiKeyPadMenuItem, + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, + EuiLoadingSpinner, +} from '../../../../src/components'; +import { ThemeContext } from '../../components/with_theme'; +import { typesOfPanelColors } from './_types_of_panel_colors'; +// @ts-ignore Importing from JS file +import { typesOfUseCases } from './_types_of_use_cases'; +import { useIsWithinBreakpoints } from '../../../../src/services/hooks'; +import { GuideSection } from '../../components/guide_section/guide_section'; +import { GuideSectionTypes } from '../../components/guide_section/guide_section_types'; + +// images dark +import darkSidebar from '../../images/empty-prompt/thumbnail_dark_page-sidebar.svg'; +import darkEmpty from '../../images/empty-prompt/thumbnail_dark_page-empty.svg'; +import darkMultiple from '../../images/empty-prompt/thumbnail_dark_page-multiple.svg'; +import darkContent from '../../images/empty-prompt/thumbnail_dark_empty_content.svg'; + +// images light +import lightSidebar from '../../images/empty-prompt/thumbnail_light_page-sidebar.svg'; +import lightEmpty from '../../images/empty-prompt/thumbnail_light_page-empty.svg'; +import lightMultiple from '../../images/empty-prompt/thumbnail_light_page-multiple.svg'; +import lightContent from '../../images/empty-prompt/thumbnail_light_empty_content.svg'; + +import sideNavSvg from '../../images/side_nav.svg'; +import singleSvg from '../../images/single.svg'; + +export default () => { + const themeContext = useContext(ThemeContext); + + /** + * Setup theme based on current light/dark theme + */ + const isDarkTheme = themeContext.theme.includes('dark'); + + const useCasesOptions: EuiRadioGroupOption[] = Object.values( + typesOfUseCases + ).map((item: any) => { + return { + id: item.id, + label: item.label, + }; + }); + + const errorValue = typesOfUseCases.error.id; + const [radioUseCaseId, setRadioUseCaseId] = useState< + EuiRadioGroupOption['id'] + >(typesOfUseCases.firstUse.id); + + const [panelProps, setPanelProps] = useState({ color: 'plain' }); + const [thumbnail, setThumbnail] = useState('sidebar'); + const [isDisabledMultipleThumb, setIsDisabledMultipleThumb] = useState(false); + + const onSelectThumbnail = (thumbnailName: string) => { + setThumbnail(thumbnailName); + }; + + const isSidebar = thumbnail === 'sidebar'; + const isEmpty = thumbnail === 'empty'; + const isMultiple = thumbnail === 'multiple'; + + const onChangeUseCase = (id: EuiRadioGroupOption['id']) => { + setRadioUseCaseId(id); + }; + + const [ + visibleRecommendedPanelColorText, + setVisibleRecommendedPanelColorText, + ] = useState(typesOfPanelColors.subdued.text); + + const isMobileSize = useIsWithinBreakpoints(['xs', 's']); + + const sideNav = ( + + ); + + useEffect(() => { + if (isSidebar && radioUseCaseId !== errorValue) { + setVisibleRecommendedPanelColorText(typesOfPanelColors.subdued.text); + setPanelProps(typesOfPanelColors.subdued.props); + } else if (isEmpty && radioUseCaseId !== errorValue) { + setVisibleRecommendedPanelColorText(typesOfPanelColors.plain.text); + setPanelProps(typesOfPanelColors.plain.props); + } else if (isMultiple && radioUseCaseId !== errorValue) { + setVisibleRecommendedPanelColorText(typesOfPanelColors.multiple.text); + setPanelProps(typesOfPanelColors.multiple.props); + } else { + setVisibleRecommendedPanelColorText(typesOfPanelColors.error.text); + setPanelProps(typesOfPanelColors.error.props); + } + + if ( + radioUseCaseId === 'noPrivileges' || + radioUseCaseId === 'errorPages' || + radioUseCaseId === 'forbidden' || + radioUseCaseId === 'noResults' + ) { + // if the `multiple` thumb is selected when we changing the use case for `noPrivileges`, `errorPages`, `forbidden` or `noResults` we change the selection for the first thumb + // because these use cases don't work for a `multiple` page layout + if (thumbnail === 'multiple') { + setThumbnail('sidebar'); + } + + setIsDisabledMultipleThumb(true); + } else { + setIsDisabledMultipleThumb(false); + } + }, [radioUseCaseId, errorValue, isSidebar, isEmpty, isMultiple, thumbnail]); + + const currentUseCaseInfo = typesOfUseCases[radioUseCaseId].info; + + const currentUseCaseExample = typesOfUseCases[radioUseCaseId].example; + + let icon; + + if (currentUseCaseExample.iconLoading && radioUseCaseId === 'loading') { + // if is multiple just show a loading spinner + if (isMultiple) { + icon = { icon: }; + } else { + icon = { + icon: currentUseCaseExample.iconLoading, + }; + } + } else if (currentUseCaseExample.iconType) { + icon = { iconType: currentUseCaseExample.iconType }; + } else { + const iconImg: string = isDarkTheme + ? currentUseCaseExample.iconDark! + : currentUseCaseExample.iconLight!; + + icon = { + icon: , + }; + } + + const layout = currentUseCaseExample.layout + ? { layout: currentUseCaseExample.layout } + : { layout: 'vertical' }; + + const titleSize = isMultiple ? 's' : 'm'; + const multipleLoadingPanel = isMultiple && radioUseCaseId === 'loading'; + + const multipleLoadingPanelStyles = multipleLoadingPanel && { + style: { + minWidth: '100%', + width: '100%', + }, + }; + + const body = currentUseCaseExample.body && { + body: currentUseCaseExample.body, + }; + + const actions = currentUseCaseExample.actions && { + actions: currentUseCaseExample.actions, + }; + + const euiEmptyPromptPreview = ( + + ); + + let demo; + + if (isSidebar) { + demo = ( + + {euiEmptyPromptPreview} + + ); + } else if (isEmpty) { + demo = ( + + {euiEmptyPromptPreview} + + ); + } else if (isMultiple) { + demo = ( + + + {euiEmptyPromptPreview} + + + + + + + + + + + + + + + + + + ); + } + + const code = reactElementToJSXString(demo); + + return ( + <> + + + +

What is the use case?

+ + ), + }} + /> + + + + +

+ What is the page template? +

+
+ + + + + onSelectThumbnail('sidebar')} + > + + + onSelectThumbnail('empty')} + > + + + {!isDisabledMultipleThumb && ( + onSelectThumbnail('multiple')} + > + + + )} + + + +
+ + + + Description + + {currentUseCaseInfo.description} + + + Goal + + {currentUseCaseInfo.goal} + + + {currentUseCaseInfo.action && ( + <> + Action + + {currentUseCaseInfo.action} + + + )} + + + Recommended panel color + + + {visibleRecommendedPanelColorText} + + + +
{/* */}
+
+
+ + {demo}} + source={[ + { + type: GuideSectionTypes.STRING_JS, + code: code, + }, + ]} + /> + + ); +}; diff --git a/src-docs/src/views/empty_prompt/_types_of_panel_colors.tsx b/src-docs/src/views/empty_prompt/_types_of_panel_colors.tsx new file mode 100644 index 00000000000..0cba5330baf --- /dev/null +++ b/src-docs/src/views/empty_prompt/_types_of_panel_colors.tsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { EuiCode } from '../../../../src/components'; + +export const typesOfPanelColors: any = { + subdued: { + id: 'subdued', + text: ( + <> +

+ Set {'color="subdued"'} to make users not getting + distracted and focus on the content. +

+

+ Consider the transparent color if the empty prompt is contained in + another component. +

+ + ), + props: { color: 'subdued' }, + }, + plain: { + id: 'plain', + text: ( + <> +

+ Set {'color="plain”'} to make users getting focus + on the content +

+

+ Consider the transparent color if the empty prompt is contained in + another component. +

+ + ), + props: { color: 'plain' }, + }, + error: { + id: 'error', + text: ( +

+ Set {'color="danger'} to emphasize that an error + happened. +

+ ), + props: { color: 'danger' }, + }, + multiple: { + id: 'multiple', + text: ( + <> +

+ Set {'color="plain” and hasBorder={true}'} when you + have multiple panels on the page. The other panels should also have + borders to ensure consistency. +

+

+ Consider the transparent color if the empty prompt is contained in + another component. +

+ + ), + props: { color: 'plain', hasBorder: true }, + }, +}; diff --git a/src-docs/src/views/empty_prompt/_types_of_use_cases.tsx b/src-docs/src/views/empty_prompt/_types_of_use_cases.tsx new file mode 100644 index 00000000000..5153bb39997 --- /dev/null +++ b/src-docs/src/views/empty_prompt/_types_of_use_cases.tsx @@ -0,0 +1,290 @@ +import React, { ReactNode } from 'react'; +import { + EuiButton, + EuiButtonEmpty, + EuiLoadingLogo, + EuiTitle, + EuiLink, + EuiFlexGroup, + EuiFlexItem, + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, + IconType, +} from '../../../../src/components'; + +import pageNotFoundLight from '../../images/empty-prompt/404_rainy_cloud_light.png'; +import pageNotFoundDark from '../../images/empty-prompt/404_rainy_cloud_dark.png'; +import noResultsLight from '../../images/empty-prompt/no-results--light.svg'; +import noResultsDark from '../../images/empty-prompt/no-results--dark.svg'; + +export const typesOfUseCases: { + [key: string]: { + id: string; + label: string; + info: { + description: ReactNode; + goal: ReactNode; + action?: ReactNode; + }; + example: { + iconLoading?: ReactNode; + iconLight?: string; + iconDark?: string; + iconType?: IconType; + title: ReactNode; + body?: ReactNode; + actions?: ReactNode[]; + layout?: 'horizontal' | 'vertical'; + footer?: ReactNode; + }; + footer?: ReactNode; + }; +} = { + firstUse: { + id: 'firstUse', + label: 'First time use', + info: { + description:

First time use.

, + goal: ( + <> +

Help users understand how they can start using the product.

+

+ For no data use cases, consider using a{' '} + EuiCard. In Kibana, you + just need to pass a no data configuration into your{' '} + + KibanaPageTemplate + {' '} + to display a specific UI that guides users to add data. +

+ + ), + action: ( +

+ Actions specific to first use. For example: “Add cases”, “Create job”, + “Add workpad”. +

+ ), + }, + example: { + iconType: 'logoSecurity', + title:

Start adding cases

, + body:

Add a new case or change your filter settings.

, + actions: [ + + Add a case + , + ], + }, + footer: ( + + + +

Want to learn more?

+
+ + + Read documentation + + +
+ + +

Sure you have data?

+
+ + {}} + iconType="refresh" + iconSide="right" + iconSize="s" + flush="both" + size="s" + > + Check for new data + + +
+
+ ), + }, + noPrivileges: { + id: 'noPrivileges', + label: 'No privileges', + info: { + description:

No privileges to access a feature.

, + goal: ( +

+ Help users understand why they don't have privileges to a feature + and what actions to take to get access. +

+ ), + action:

Request permission.

, + }, + + example: { + iconType: 'lock', + title:

Contact your administrator for access

, + body:

To view cases in this space, you need additional privileges.

, + }, + }, + noResults: { + id: 'noResults', + label: 'No results', + info: { + description:

No results matched the search.

, + goal: ( +

+ Help users understand why the search didn't match any results and + what they can do to get better results. +

+ ), + action: ( +

+ Refresh, try again, reformat the data, or try another action specific + to the error. +

+ ), + }, + example: { + iconLight: noResultsLight, + iconDark: noResultsDark, + title:

No results match your search criteria

, + layout: 'horizontal', + body: ( + + + Expand your time range + + + Try searching over a longer period of time. + + + Adjust your query + + Try searching for a different combination of terms. + + + ), + }, + }, + error: { + id: 'error', + label: 'Error loading data', + info: { + description:

An error happened when loading the data.

, + goal: ( +

+ Help users understand why they're facing an error and what they + can do to solve it. +

+ ), + }, + example: { + iconType: 'alert', + title:

Unable to load your dashboards

, + body: ( +

+ There was a problem loading the Dashboard application. Contact your + administrator for help. +

+ ), + }, + }, + errorPages: { + id: 'errorPages', + label: 'Error pages (4xx and 5xx)', + info: { + description: ( +

+ The error pages come from client and server errors — the 4xx and 5xx + status code classes. +

+ ), + goal:

Help users understand there is a client or server error.

, + action:

Go home or go back.

, + }, + example: { + iconLight: pageNotFoundLight, + iconDark: pageNotFoundDark, + title:

Page not found

, + body: ( +

+ Sorry, we can't find the page you're looking for. It might + have been removed or renamed, or maybe it never existed. +

+ ), + actions: [ + + Go home + , + + Go back + , + ], + }, + }, + licenseUpgrade: { + id: 'licenseUpgrade', + label: 'License upgrade', + info: { + description:

No license to use a feature.

, + goal: ( +

+ Help users understand that they don't have the required license + to access a feature and what actions they need to perform to upgrade + the license. +

+ ), + action:

Start a trial or upgrade the license.

, + }, + example: { + iconType: 'logoKibana', + title:

Do more with Kibana!

, + body: ( +

+ Start a free trial or upgrade your license to use anomaly detection. +

+ ), + actions: [ + + Upgrade + , + Start a free trial, + ], + footer: ( + <> + +

Want to learn more?

+
+ + Read documentation + + + ), + }, + }, + loading: { + id: 'loading', + label: 'Loading', + info: { + description:

The page or content is loading.

, + goal:

Help users understand that the data is loading.

, + }, + example: { + iconLoading: , + title:

Loading dashboards

, + }, + }, +}; diff --git a/src-docs/src/views/empty_prompt/empty_prompt_error.tsx b/src-docs/src/views/empty_prompt/empty_prompt_error.tsx index 324aaefa031..c4867bf4671 100644 --- a/src-docs/src/views/empty_prompt/empty_prompt_error.tsx +++ b/src-docs/src/views/empty_prompt/empty_prompt_error.tsx @@ -6,7 +6,7 @@ export default () => ( Error loading Dashboards} + title={

Unable to load your dashboards

} body={

There was an error loading the Dashboard application. Contact your diff --git a/src-docs/src/views/empty_prompt/empty_prompt_example.js b/src-docs/src/views/empty_prompt/empty_prompt_example.js index e4745fa0277..16a42229dfd 100644 --- a/src-docs/src/views/empty_prompt/empty_prompt_example.js +++ b/src-docs/src/views/empty_prompt/empty_prompt_example.js @@ -163,12 +163,12 @@ export const EmptyPromptExample = { color prop will also attempt to adjust the{' '} iconColor and footer color.

- {/* Commenting out for now, as the Guidelines don't yet specify. +

Read the{' '} usage guidelines to better understand when to use certain panel props. -

*/} +

diff --git a/src-docs/src/views/empty_prompt/empty_prompt_layout.tsx b/src-docs/src/views/empty_prompt/empty_prompt_layout.tsx index 6db4c5045c0..eee99f89898 100644 --- a/src-docs/src/views/empty_prompt/empty_prompt_layout.tsx +++ b/src-docs/src/views/empty_prompt/empty_prompt_layout.tsx @@ -8,7 +8,7 @@ import { EuiImage, } from '../../../../src/components'; -import illustration from '../../images/empty-prompt_illustration.svg'; +import illustration from '../../images/empty-prompt/illustration.svg'; export default () => { return ( diff --git a/src-docs/src/views/empty_prompt/empty_prompt_multiple_types.tsx b/src-docs/src/views/empty_prompt/empty_prompt_multiple_types.tsx index 9d7a8c86485..5b510516cd2 100644 --- a/src-docs/src/views/empty_prompt/empty_prompt_multiple_types.tsx +++ b/src-docs/src/views/empty_prompt/empty_prompt_multiple_types.tsx @@ -6,10 +6,10 @@ import { GuideSection } from '../../components/guide_section/guide_section'; import { GuideSectionTypes } from '../../components/guide_section/guide_section_types'; import { PanelColor } from '../../../../src/components/panel/panel'; -import pageError from './prompt_types/page_error'; -const pageErrorSource = require('!!raw-loader!./prompt_types/page_error'); -import noPermission from './prompt_types/no_permission'; -const noPermissionSource = require('!!raw-loader!./prompt_types/no_permission'); +import errorPages from './prompt_types/page_not_found'; +const errorPagesSource = require('!!raw-loader!./prompt_types/page_not_found'); +import noPrivileges from './prompt_types/no_permission'; +const noPrivilegesSource = require('!!raw-loader!./prompt_types/no_permission'); import licenseUpgrade from './prompt_types/license_upgrade'; const licenseUpgradeSource = require('!!raw-loader!./prompt_types/license_upgrade'); import complex from './prompt_types/complex'; @@ -24,16 +24,16 @@ export default () => { demoBackground?: PanelColor; }> = [ { - value: 'pageError', + value: 'errorPages', text: 'Page not found', - component: pageError, - source: pageErrorSource, + component: errorPages, + source: errorPagesSource, }, { - value: 'noPermission', + value: 'noPrivileges', text: 'No permission', - component: noPermission, - source: noPermissionSource, + component: noPrivileges, + source: noPrivilegesSource, }, { value: 'licenseUpgrade', diff --git a/src-docs/src/views/empty_prompt/empty_prompt_page_template.tsx b/src-docs/src/views/empty_prompt/empty_prompt_page_template.tsx index b96ed46af43..1f7cb750249 100644 --- a/src-docs/src/views/empty_prompt/empty_prompt_page_template.tsx +++ b/src-docs/src/views/empty_prompt/empty_prompt_page_template.tsx @@ -8,7 +8,7 @@ import { EuiLink, EuiImage, } from '../../../../src/components'; -import illustration from '../../images/empty-prompt_illustration.svg'; +import illustration from '../../images/empty-prompt/illustration.svg'; export default () => ( { emptyPromptProps = { color: 'danger', iconType: 'alert', - title:

Error loading Dashboards

, + title:

Unable to load your dashboards

, body: (

There was an error loading the Dashboard application. Contact your diff --git a/src-docs/src/views/empty_prompt/guidelines.tsx b/src-docs/src/views/empty_prompt/guidelines.tsx index 35fda9eea6e..99474ad67ac 100644 --- a/src-docs/src/views/empty_prompt/guidelines.tsx +++ b/src-docs/src/views/empty_prompt/guidelines.tsx @@ -1,23 +1,24 @@ import React from 'react'; -// @ts-ignore Importing from JS -import { GuideRuleTitle } from '../../components'; +// @ts-ignore Importing from JS file +import { GuideRule, GuideRuleExample, GuideRuleTitle } from '../../components'; import { EuiTitle, EuiText, EuiSpacer, - EuiFlexGroup, - EuiFlexItem, EuiImage, - EuiTable, - EuiTableHeader, - EuiTableHeaderCell, - EuiTableBody, - EuiTableRow, - EuiTableRowCell, + EuiAspectRatio, } from '../../../../src/components'; +import TypesOfEmptyStates from './_types_of_empty_states'; -import imgAnatomy from '../../images/empty-prompt_anatomy.svg'; +import vertical from '../../images/empty-prompt/thumbnail_vertical.svg'; +import horizontal from '../../images/empty-prompt/thumbnail_horizontal.svg'; +import iconDont from '../../images/empty-prompt/thumbnail_icon-dont.svg'; +import iconDo from '../../images/empty-prompt/thumbnail_icon-do.svg'; +import multipleDo from '../../images/empty-prompt/thumbnail_multiple-do.svg'; +import multipleDont from '../../images/empty-prompt/thumbnail_multiple-dont.svg'; +import inlineLink from '../../images/empty-prompt/thumbnail_inline-link.svg'; +import footerLink from '../../images/empty-prompt/thumbnail_footer-link.svg'; export default () => ( <> @@ -27,174 +28,211 @@ export default () => ( - +

- A useful empty state will let the user know what’s happening, why it’s - happening, and what to do about it. If done right, it can can contribute - to a more compelling user experience and add more value to the business. + A useful empty state will let the user know what's happening, why + it's happening, and what to do about it. It can contribute to a + more compelling user experience and add more value to the business if + done right.

To make the empty state clear, follow this pattern:

+ + + + +