diff --git a/amundsen_application/static/css/_icons.scss b/amundsen_application/static/css/_icons.scss index 7486cfb67..948733f19 100644 --- a/amundsen_application/static/css/_icons.scss +++ b/amundsen_application/static/css/_icons.scss @@ -6,6 +6,9 @@ $icon-size: 24px; $icon-small-size: 16px; +// Icons +// Lookout! When you update one of these, please update the enums on +// /static/js/interfaces/Enums.ts // Map of Database names and icon paths $data-stores: ( database: '/static/images/icons/Database.svg', diff --git a/amundsen_application/static/js/components/DashboardPage/index.tsx b/amundsen_application/static/js/components/DashboardPage/index.tsx index 426329eab..62dd40204 100644 --- a/amundsen_application/static/js/components/DashboardPage/index.tsx +++ b/amundsen_application/static/js/components/DashboardPage/index.tsx @@ -4,28 +4,23 @@ import * as React from 'react'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; -import { Link } from 'react-router-dom'; import { RouteComponentProps } from 'react-router'; -import * as qs from 'simple-query-string'; - import * as ReactMarkdown from 'react-markdown'; -import AvatarLabel from 'components/common/AvatarLabel'; +import { getDashboard } from 'ducks/dashboard/reducer'; +import { GetDashboardRequest } from 'ducks/dashboard/types'; +import { GlobalState } from 'ducks/rootReducer'; +import { logClick } from 'ducks/utilMethods'; + import Breadcrumb from 'components/common/Breadcrumb'; import BookmarkIcon from 'components/common/Bookmark/BookmarkIcon'; import EditableSection from 'components/common/EditableSection'; import LoadingSpinner from 'components/common/LoadingSpinner'; import TabsComponent from 'components/common/TabsComponent'; -import { getDashboard } from 'ducks/dashboard/reducer'; -import { GetDashboardRequest } from 'ducks/dashboard/types'; -import { GlobalState } from 'ducks/rootReducer'; -import { logClick } from 'ducks/utilMethods'; -import { DashboardMetadata } from 'interfaces/Dashboard'; import DashboardOwnerEditor from 'components/DashboardPage/DashboardOwnerEditor'; import QueryList from 'components/DashboardPage/QueryList'; import ChartList from 'components/DashboardPage/ChartList'; import ResourceStatusMarker from 'components/common/ResourceStatusMarker'; -import { formatDateTimeShort } from 'utils/dateUtils'; import ResourceList from 'components/common/ResourceList'; import { ADD_DESC_TEXT, @@ -37,14 +32,15 @@ import { STATUS_TEXT, } from 'components/DashboardPage/constants'; import TagInput from 'components/common/Tags/TagInput'; -import { ResourceType } from 'interfaces'; +import { NO_TIMESTAMP_TEXT } from 'components/constants'; import { getSourceDisplayName, getSourceIconClass } from 'config/config-utils'; -import { BadgeStyle } from 'config/config-types'; - +import { formatDateTimeShort } from 'utils/dateUtils'; import { getLoggingParams } from 'utils/logUtils'; -import { NO_TIMESTAMP_TEXT } from 'components/constants'; +import { ResourceType } from 'interfaces'; +import { DashboardMetadata } from 'interfaces/Dashboard'; + import ImagePreview from './ImagePreview'; import './styles.scss'; diff --git a/amundsen_application/static/js/components/TableDetail/RequestMetadataForm/index.spec.tsx b/amundsen_application/static/js/components/TableDetail/RequestMetadataForm/index.spec.tsx index 98766f959..c411ee989 100644 --- a/amundsen_application/static/js/components/TableDetail/RequestMetadataForm/index.spec.tsx +++ b/amundsen_application/static/js/components/TableDetail/RequestMetadataForm/index.spec.tsx @@ -3,9 +3,6 @@ import * as React from 'react'; import { shallow } from 'enzyme'; - -import FlashMessage from 'components/common/FlashMessage'; - import globalState from 'fixtures/globalState'; import { NotificationType, diff --git a/amundsen_application/static/js/components/TableDetail/RequestMetadataForm/index.tsx b/amundsen_application/static/js/components/TableDetail/RequestMetadataForm/index.tsx index 58c4d6a20..92d33bf6f 100644 --- a/amundsen_application/static/js/components/TableDetail/RequestMetadataForm/index.tsx +++ b/amundsen_application/static/js/components/TableDetail/RequestMetadataForm/index.tsx @@ -16,12 +16,12 @@ import { } from 'interfaces'; import FlashMessage from 'components/common/FlashMessage'; +import { ImageIconType } from 'interfaces/Enums'; import { GlobalState } from 'ducks/rootReducer'; import { CloseRequestAction, - OpenRequestAction, SubmitNotificationRequest, } from 'ducks/notification/types'; import { @@ -84,7 +84,7 @@ export class RequestMetadataForm extends React.Component< renderFlashMessage = () => { return ( diff --git a/amundsen_application/static/js/components/common/Card/card.story.tsx b/amundsen_application/static/js/components/common/Card/card.story.tsx new file mode 100644 index 000000000..41b416e1e --- /dev/null +++ b/amundsen_application/static/js/components/common/Card/card.story.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import StorySection from '../StorySection'; +import Card from '.'; + +const stories = storiesOf('Components/Cards', module); + +stories.add('Cards', () => ( + <> + + + + + + + + + + +)); diff --git a/amundsen_application/static/js/components/common/FlashMessage/flashMessage.story.tsx b/amundsen_application/static/js/components/common/FlashMessage/flashMessage.story.tsx new file mode 100644 index 000000000..1e8d9c37e --- /dev/null +++ b/amundsen_application/static/js/components/common/FlashMessage/flashMessage.story.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import { ImageIconType } from 'interfaces/Enums'; +import StorySection from '../StorySection'; +import FlashMessage from '.'; + +const stories = storiesOf('Components/Flash Message', module); + +stories.add('Flash Message', () => ( + <> + + { + alert('message closed!'); + }} + /> + + + { + alert('message closed!'); + }} + /> + + +)); diff --git a/amundsen_application/static/js/components/common/FlashMessage/index.spec.tsx b/amundsen_application/static/js/components/common/FlashMessage/index.spec.tsx index 19dc2416e..c5890e80d 100644 --- a/amundsen_application/static/js/components/common/FlashMessage/index.spec.tsx +++ b/amundsen_application/static/js/components/common/FlashMessage/index.spec.tsx @@ -5,6 +5,7 @@ import * as React from 'react'; import { shallow } from 'enzyme'; +import { ImageIconType } from 'interfaces/Enums'; import FlashMessage, { FlashMessageProps } from '.'; describe('FlashMessage', () => { @@ -22,20 +23,23 @@ describe('FlashMessage', () => { describe('render', () => { let props: FlashMessageProps; let wrapper; + beforeAll(() => { - const setupResult = setup(); - props = setupResult.props; - wrapper = setupResult.wrapper; + ({ props, wrapper } = setup()); }); describe('iconClass logic', () => { it('if no iconClass, does not render img', () => { - expect(wrapper.find('img').exists()).toBe(false); + const expected = 0; + const actual = wrapper.find('img').length; + + expect(actual).toEqual(expected); }); it('if iconClass, renders img with correct className', () => { - const testClass = 'icon-mail'; + const testClass = ImageIconType.MAIL; const { wrapper } = setup({ iconClass: testClass }); + expect(wrapper.find('img').props()).toMatchObject({ className: `icon ${testClass}`, }); @@ -43,13 +47,17 @@ describe('FlashMessage', () => { }); it('renders correct message text', () => { - expect(wrapper.find('div.message').text()).toBe(props.message); + const expected = props.message; + const actual = wrapper.find('.message').text(); + + expect(actual).toEqual(expected); }); it('renders correct button', () => { - expect(wrapper.find('button.btn.btn-close').props().onClick).toBe( - props.onClose - ); + const expected = props.onClose; + const actual = wrapper.find('button.btn.btn-close').props().onClick; + + expect(actual).toEqual(expected); }); }); }); diff --git a/amundsen_application/static/js/components/common/FlashMessage/index.tsx b/amundsen_application/static/js/components/common/FlashMessage/index.tsx index 33ec1db3b..f04d6cc0b 100644 --- a/amundsen_application/static/js/components/common/FlashMessage/index.tsx +++ b/amundsen_application/static/js/components/common/FlashMessage/index.tsx @@ -2,12 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 import * as React from 'react'; +import { ImageIconType } from 'interfaces/Enums'; import * as Constants from './constants'; import './styles.scss'; export interface FlashMessageProps { - iconClass?: string | null; + iconClass?: ImageIconType | null; message: string; onClose: (event: React.MouseEvent) => void; } @@ -19,8 +20,10 @@ const FlashMessage: React.FC = ({ }: FlashMessageProps) => { return (
- {iconClass && } -
{message}
+
+ {iconClass && } +

{message}

+
diff --git a/amundsen_application/static/js/components/common/FlashMessage/styles.scss b/amundsen_application/static/js/components/common/FlashMessage/styles.scss index 255443a59..06b438047 100644 --- a/amundsen_application/static/js/components/common/FlashMessage/styles.scss +++ b/amundsen_application/static/js/components/common/FlashMessage/styles.scss @@ -2,22 +2,35 @@ // SPDX-License-Identifier: Apache-2.0 @import 'variables'; +@import 'typography'; + +$flash-message-height: 56px; +$flash-message-border-radius: 4px; +$flash-message-message-line-height: 24px; .flash-message { background-color: $body-bg-dark; - border-radius: 6px; + border-radius: $flash-message-border-radius; color: $white; display: flex; - height: 56px; - padding: $spacer-2 $spacer-1; + height: $flash-message-height; + padding: $spacer-2; + padding-right: $spacer-1 * 1.5; + justify-content: space-between; .message { - line-height: 24px; - margin-right: $spacer-2; + @extend %text-body-w3; + + line-height: $flash-message-message-line-height; + margin: 0; + display: inline; + } + + .icon { + margin: 0 $spacer-1 0 0; } - .icon, .btn-close { - margin: auto $spacer-1; + margin: auto 0 auto $spacer-3; } } diff --git a/amundsen_application/static/js/components/common/StorySection/index.tsx b/amundsen_application/static/js/components/common/StorySection/index.tsx new file mode 100644 index 000000000..516445dbf --- /dev/null +++ b/amundsen_application/static/js/components/common/StorySection/index.tsx @@ -0,0 +1,21 @@ +import React, { ReactNode } from 'react'; + +type BlockProps = { + children: ReactNode; + title: string; + text?: string | ReactNode; +}; + +const StorySection: React.FC = ({ + children, + text, + title, +}: BlockProps) => ( +
+

{title}

+ {text &&

{text}

} + {children} +
+); + +export default StorySection; diff --git a/amundsen_application/static/js/interfaces/Enums.ts b/amundsen_application/static/js/interfaces/Enums.ts index a81255524..ccd499817 100644 --- a/amundsen_application/static/js/interfaces/Enums.ts +++ b/amundsen_application/static/js/interfaces/Enums.ts @@ -17,3 +17,47 @@ export enum SearchType { PAGINATION = 'update_page', SUBMIT_TERM = 'submit_search_term', } + +// Image-based Icon types from _icons.scss +export enum ImageIconType { + ALERT = 'icon-alert', + BOOKMARK = 'icon-bookmark', + BOOKMARK_FILLED = 'icon-bookmark-filled', + DELETE = 'icon-delete', + RED_TRIANGLE_WARNING = 'icon-red-triangle-warning', + DOWN = 'icon-down', + EDIT = 'icon-edit', + HELP = 'icon-help', + GITHUB = 'icon-github', + LEFT = 'icon-left', + LOADING = 'icon-loading', + MAIL = 'icon-mail', + PLUS = 'icon-plus', + PLUS_CIRCLE = 'icon-plus-circle', + PREVIEW = 'icon-preview', + REFRESH = 'icon-refresh', + RIGHT = 'icon-right', + SEARCH = 'icon-search', + SEND = 'icon-send', + SLACK = 'icon-slack', + UP = 'icon-up', + USER = 'icon-user', + MORE = 'icon-more', +} + +// Icon types from _icons.scss +export enum IconType { + CHECK = 'icon-check', + USERS = 'icon-users', + DASHBOARD = 'icon-dashboard', + MODE = 'icon-mode', + REDASH = 'icon-redash', + TABLEAU = 'icon-tableau', + DATABASE = 'icon-database', + HIVE = 'icon-hive', + BIGQUERY = 'icon-bigquery', + DRUID = 'icon-druid', + PRESTO = 'icon-presto', + POSTGRES = 'icon-postgres', + REDSHIFT = 'icon-redshift', +} diff --git a/amundsen_application/static/js/stories/colors.story.tsx b/amundsen_application/static/js/stories/colors.story.tsx new file mode 100644 index 000000000..3f37415ee --- /dev/null +++ b/amundsen_application/static/js/stories/colors.story.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { storiesOf } from '@storybook/react'; + +import StorySection from '../components/common/StorySection'; + +const stories = storiesOf('Attributes/Colors', module); + +const COLOR_BLOCK_SIZE = '80px'; + +type ColorBlockProps = { + color: string; + title: string; +}; + +const ColorBlock: React.FC = ({ + color, + title, +}: ColorBlockProps) => ( +
+

{title}

+
+
+); + +stories.add('Colors', () => ( + <> + +
+ + + + + +
+
+ +
+ + + + + +
+
+ +)); diff --git a/amundsen_application/static/js/stories/typography.story.tsx b/amundsen_application/static/js/stories/typography.story.tsx index 3e62e8941..0bc1f8acc 100644 --- a/amundsen_application/static/js/stories/typography.story.tsx +++ b/amundsen_application/static/js/stories/typography.story.tsx @@ -1,59 +1,93 @@ -import React from 'react'; +import React, { ReactNode } from 'react'; + +import StorySection from '../components/common/StorySection'; export default { title: 'Attributes/Typography', }; -export const Typography = () => { +export const TypographyUpdated = () => { return ( <> -

Headings

-
-

Raw h1

-

Raw h2

-

Raw h3

-

Raw h4

-
Raw h5
-
Raw h6
-
-

Heading with .title-1

-

Heading with .title-2

-

Heading with .title-3

-

Heading with .subtitle-1

-

Heading with .subtitle-2

-

Heading with .subtitle-3

+ + <> +

Heading with .text-headline-w1

+

Heading with .text-headline-w2

+

Heading with .text-headline-w3

+ +
+ + <> +

Title with .text-title-w1

+

Title with .text-title-w2

+

Title with .text-title-w3

+ +
+ + <> +

Subtitle with .text-subtitle-w1

+

Subtitle with .text-subtitle-w2

+

Subtitle with .text-subtitle-w3

+ +
+ + <> +

Subtitle with .text-body-w1

+

Subtitle with .text-body-w2

+

Subtitle with .text-body-w3

+ +
); }; -Typography.story = { - name: 'Headings', +TypographyUpdated.story = { + name: 'Typography', }; -export const Body = () => { +export const Typography = () => { return ( <> -

Body

-
-

Raw p

-
-

Paragraph with .body-1

-

Paragraph with .body-2

-

Paragraph with .body-3

-

Paragraph with .body-secondary-3

-

Paragraph with .body-placeholder

-

Paragraph with .body-link

-

Paragraph with .caption

-

Paragraph with .column-name

-

Paragraph with .resource-type

-

Paragraph with .helper-text

-

Paragraph with .text-placeholder

-

Paragraph with .text-secondary

-

Paragraph with .text-primary

+ + <> +

Raw h1

+

Raw h2

+

Raw h3

+

Raw h4

+
Raw h5
+
Raw h6
+
+

Heading with .title-1

+

Heading with .title-2

+

Heading with .title-3

+

Heading with .subtitle-1

+

Heading with .subtitle-2

+

Heading with .subtitle-3

+ +
+ + <> +

Raw p

+
+

Paragraph with .body-1

+

Paragraph with .body-2

+

Paragraph with .body-3

+

Paragraph with .body-secondary-3

+

Paragraph with .body-placeholder

+

Paragraph with .body-link

+

Paragraph with .caption

+

Paragraph with .column-name

+

Paragraph with .resource-type

+

Paragraph with .helper-text

+

Paragraph with .text-placeholder

+

Paragraph with .text-secondary

+

Paragraph with .text-primary

+ +
); }; -Body.story = { - name: 'Body Text', +Typography.story = { + name: 'Deprecated: Headings & Body', }; diff --git a/amundsen_application/static/js/stories/welcome.story.tsx b/amundsen_application/static/js/stories/welcome.story.tsx index 996370099..26d1a1a47 100644 --- a/amundsen_application/static/js/stories/welcome.story.tsx +++ b/amundsen_application/static/js/stories/welcome.story.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { Welcome } from '@storybook/react/demo'; +import StorySection from '../components/common/StorySection'; + export default { title: 'Overview/Introduction', component: Welcome, @@ -9,31 +11,36 @@ export default { export const Introduction = () => { return ( <> -

Welcome to Amundsen's Component Library!

-

- A development area for developing new{' '} - presentational components -

-

- Do you ever miss having a “workshop” to develop new components before - hooking them with the real data? Look no more, here is the place! -

-

In this environment you can:

-
    -
  • Quickly develop new components for using them on Amundsen
  • -
  • See what components are available already
  • -
  • Be consistent with the Amundsen styling
  • -
  • Create manual tests for your components
  • -
  • - Avoid the whole syncing thing while developing your presentational - components -
  • -
  • - Clear the path to eventually move reusable components into the Data - Product Language (DPL) -
  • -
  • Prototype something really quick to show around
  • -
+ + A development area for developing new{' '} + presentational components + + } + > +

+ Do you ever miss having a “workshop” to develop new components before + hooking them with the real data? Look no more, here is the place! +

+

In this environment you can:

+
    +
  • Quickly develop new components for using them on Amundsen
  • +
  • See what components are available already
  • +
  • Be consistent with the Amundsen styling
  • +
  • Create manual tests for your components
  • +
  • + Avoid the whole syncing thing while developing your presentational + components +
  • +
  • + Clear the path to eventually move reusable components into the Data + Product Language (DPL) +
  • +
  • Prototype something really quick to show around
  • +
+
); }; diff --git a/amundsen_application/static/package.json b/amundsen_application/static/package.json index 5110cfc01..7e36f0756 100644 --- a/amundsen_application/static/package.json +++ b/amundsen_application/static/package.json @@ -25,7 +25,7 @@ "stylelint": "stylelint '**/*.scss'", "stylelint:fix": "stylelint --fix '**/*.scss'", "format": "prettier --loglevel warn --write \"**/*.{ts,tsx,css,scss}\"", - "storybook": "cross-env TS_NODE_PROJECT='tsconfig.webpack.json' start-storybook -p 6006", + "storybook": "cross-env TS_NODE_PROJECT='tsconfig.webpack.json' start-storybook -s ../ -p 6006", "build-storybook": "cross-env TS_NODE_PROJECT='tsconfig.webpack.json' build-storybook", "betterer": "betterer", "betterer:update": "betterer --update"