From df8250ff48a686ca94173b4ce95063ed76369cc1 Mon Sep 17 00:00:00 2001 From: Alex Khomenko Date: Fri, 16 Feb 2024 12:13:50 +0100 Subject: [PATCH] Card: Remove mdx file and render docs from the story (#82565) * Card: Generate docs from the story * Update sort * Update betterer to check for the "autodocs" tag --- .betterer.ts | 11 +- packages/grafana-ui/.storybook/preview.ts | 4 + .../grafana-ui/src/components/Card/Card.mdx | 450 ------------------ .../src/components/Card/Card.story.tsx | 254 +++++++--- 4 files changed, 199 insertions(+), 520 deletions(-) delete mode 100644 packages/grafana-ui/src/components/Card/Card.mdx diff --git a/.betterer.ts b/.betterer.ts index e6e3a066777..7439cf7fa87 100644 --- a/.betterer.ts +++ b/.betterer.ts @@ -31,9 +31,16 @@ function countUndocumentedStories() { await Promise.all( filePaths.map(async (filePath) => { // look for .mdx import in the story file - const regex = new RegExp("^import.*.mdx';$", 'gm'); + const mdxImportRegex = new RegExp("^import.*\\.mdx';$", 'gm'); + // Looks for the "autodocs" string in the file + const autodocsStringRegex = /autodocs/; + const fileText = await fs.readFile(filePath, 'utf8'); - if (!regex.test(fileText)) { + + const hasMdxImport = mdxImportRegex.test(fileText); + const hasAutodocsString = autodocsStringRegex.test(fileText); + // If both .mdx import and autodocs string are missing, add an issue + if (!hasMdxImport && !hasAutodocsString) { // In this case the file contents don't matter: const file = fileTestResult.addFile(filePath, ''); // Add the issue to the first character of the file: diff --git a/packages/grafana-ui/.storybook/preview.ts b/packages/grafana-ui/.storybook/preview.ts index effdab3a18f..e58cfed7230 100644 --- a/packages/grafana-ui/.storybook/preview.ts +++ b/packages/grafana-ui/.storybook/preview.ts @@ -50,6 +50,10 @@ const preview: Preview = { // We should be able to use the builtin alphabetical sort, but is broken in SB 7.0 // https://github.com/storybookjs/storybook/issues/22470 storySort: (a, b) => { + // Skip sorting for stories with nosort tag + if (a.tags.includes('nosort') || b.tags.includes('nosort')) { + return 0; + } if (a.title.startsWith('Docs Overview')) { if (b.title.startsWith('Docs Overview')) { return 0; diff --git a/packages/grafana-ui/src/components/Card/Card.mdx b/packages/grafana-ui/src/components/Card/Card.mdx deleted file mode 100644 index 2e604d527f7..00000000000 --- a/packages/grafana-ui/src/components/Card/Card.mdx +++ /dev/null @@ -1,450 +0,0 @@ -import { Meta, Preview, ArgTypes } from '@storybook/blocks'; -import { Card } from './Card'; -import { Button } from '../Button'; -import { IconButton } from '../IconButton/IconButton'; -import { TagList } from '../Tags/TagList'; - -export const logo = 'https://grafana.com/static/assets/img/apple-touch-icon.png'; - - - -# Card - -## Usage - -### Basic - -A basic `Card` component expects at least a heading, used as a title. - -```jsx - - Filter by name - Filter data by query. - -``` - - - - Filter by name - Filter data by query. - - - -### Multiple metadata elements - -For providing metadata elements, which can be any extra information for the card, `Card.Meta` component should be used. If metadata consists of multiple strings, each of them has to be escaped (wrapped in brackets `{}`) or better passed in as an array. - -```jsx - - Test dashboard - {['Folder: Test', 'Views: 100']} - -``` - - - - Test dashboard - {['Folder: Test', 'Views: 100']} - - - -Metadata also accepts HTML elements, which could be links, for example. For elements, that are not strings, a `key` prop has to be manually specified. - -```jsx - - Test dashboard - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - -``` - - - - Test dashboard - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - - -The separator for multiple metadata elements defaults to a vertical line `|`, but can be customised. - -```jsx - - Test dashboard - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - -``` - - - - Test dashboard - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - - -### Tags - -Tags can be rendered inside the Card, by being wrapped in `Card.Tags` component. Note that this component does not provide any tag styling and that should be handled by the children. It is recommended to use it with Grafana-UI's `TagList` component. - -```jsx - - Test dashboard - Card with a list of tags - - console.log(tag)} /> - - -``` - - - - Test dashboard - Card with a list of tags - - console.log(tag)} /> - - - - -### As a link - -Card can be used as a clickable link item by specifying `href` prop. - -```jsx - - Redirect to Grafana - Clicking this card will redirect to grafana website - -``` - - - - Redirect to Grafana - Clicking this card will redirect to grafana website - - - -### As a button - -Card can be used as a clickable buttons item by specifying `onClick` prop. - -```jsx - alert('Hello, Grafana!')}> - Hello, Grafana - Clicking this card will create an alert - -``` - - - alert('Hello, Grafana!')}> - Hello, Grafana - Clicking this card will create an alert - - - -> **Note**: When used in conjunction with [Metadata elements](#multiple-metadata-elements), clicking on any element -> inside `` will prevent the card action to be executed (either `href` to be followed or `onClick` to be called). -> -> Example: - -```jsx - alert('Hello, Grafana!')}> - Hello, Grafana - Clicking on this text (Meta) WILL NOT trigger the alert! - Clicking on this text (Description) WILL trigger the alert! - -``` - - - alert('Hello, Grafana!')}> - Hello, Grafana - Clicking on this text (Meta) WILL NOT trigger the alert! - Clicking on this text (Description) WILL trigger the alert! - - - -### Inside a list item - -To render cards in a list, it is possible to nest them inside `li` items. - -```jsx - -``` - - -
    -
  • - - List card item - Card that is rendered inside li element. - -
  • -
  • - - List card item - Card that is rendered inside li element. - -
  • -
  • - - List card item - Card that is rendered inside li element. - -
  • -
  • - - List card item - Card that is rendered inside li element. - -
  • -
-
- -### With media elements - -Cards can also be rendered with media content such icons or images. Such elements need to be wrapped in `Card.Figure` component. - -```jsx - - 1-ops-tools1-fallback - - Grafana Logo - - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - -``` - - - - 1-ops-tools1-fallback - - Grafana Logo - - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - - -### Action Cards - -Cards also accept primary and secondary actions. Usually the primary actions are displayed as buttons while secondary actions are displayed as icon buttons. The actions need to be wrappd in `Card.Actions` and `Card.SecondaryActions` components respectively. - -```jsx - - 1-ops-tools1-fallback - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - Grafana Logo - - - - - - - - - - -``` - - - - 1-ops-tools1-fallback - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - Grafana Logo - - - - - - - - - - - - -### Disabled state - -Card can have a disabled state, effectively making it and its actions non-clickable. If there are any actions, they will be disabled instead of the whole card. - -```jsx - - 1-ops-tools1-fallback - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - Grafana Logo - - -``` - - - - 1-ops-tools1-fallback - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - Grafana Logo - - - - -```jsx - - 1-ops-tools1-fallback - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - Grafana Logo - - - - - - - - - - -``` - - - - 1-ops-tools1-fallback - - Grafana - - https://ops-us-east4.grafana.net/api/prom - - - - Grafana Logo - - - - - - - - - - - - -### Selectable - -```jsx - - Option #1 - This is a really great option, you won't regret it. - - Grafana Logo - - -``` - - - - Option #1 - This is a really great option, you won't regret it. - - Grafana Logo - - - - -### Props - - diff --git a/packages/grafana-ui/src/components/Card/Card.story.tsx b/packages/grafana-ui/src/components/Card/Card.story.tsx index e54bed30b77..c53e01798b0 100644 --- a/packages/grafana-ui/src/components/Card/Card.story.tsx +++ b/packages/grafana-ui/src/components/Card/Card.story.tsx @@ -3,27 +3,27 @@ import React from 'react'; import { Button } from '../Button'; import { IconButton } from '../IconButton/IconButton'; -import { VerticalGroup } from '../Layout/Layout'; import { TagList } from '../Tags/TagList'; import { Card } from './Card'; -import mdx from './Card.mdx'; const logo = 'https://grafana.com/static/assets/img/apple-touch-icon.png'; const meta: Meta = { title: 'General/Card', component: Card, + // nosort is a custom tag used so the stories shown in docs keep the order they are defined in the file + tags: ['autodocs', 'nosort'], parameters: { - docs: { - page: mdx, - }, controls: { exclude: ['onClick', 'href', 'heading', 'description', 'className'], }, }, }; +/** + * A basic Card component expects at least a heading, used as a title. + */ export const Basic: StoryFn = (args) => { return ( @@ -36,60 +36,157 @@ export const Basic: StoryFn = (args) => { ); }; -export const AsLink: StoryFn = (args) => { +/** + * For providing metadata elements, which can be any extra information for the card, Card.Meta component should be used. + * If metadata consists of multiple strings, each of them has to be escaped (wrapped in brackets {}) or better passed in as an array. + */ +export const MultipleMetadataElements: StoryFn = (args) => { return ( - - - Filter by name - - Filter data by query. This is useful if you are sharing the results from a different panel that has many - queries and you want to only visualize a subset of that in this panel. - - - - Filter by name2 - - Filter data by query. This is useful if you are sharing the results from a different panel that has many - queries and you want to only visualize a subset of that in this panel. - - - - Production system overview - Meta tags - - + + Test dashboard + {['Folder: Test', 'Views: 100']} + ); }; -export const WithTags: StoryFn = (args) => { +/** + * Metadata also accepts HTML elements, which could be links, for example. + * For elements, that are not strings, a `key` prop has to be manually specified. + */ +export const ComplexMetadataElements: StoryFn = (args) => { return ( - - Elasticsearch – Custom Templated Query - Elastic Search + + Test dashboard + + <>Grafana + + <>https://ops-us-east4.grafana.net/api/prom + + + + ); +}; + +/** + * The separator for multiple metadata elements defaults to a vertical line `|`, but can be customised. + */ +export const MultipleMetadataWithCustomSeparator: StoryFn = (args) => { + return ( + + Test dashboard + + Grafana + + https://ops-us-east4.grafana.net/api/prom + + + + ); +}; + +/** + * Tags can be rendered inside the Card, by being wrapped in `Card.Tags` component. + * Note that this component does not provide any tag styling and that should be handled by the children. + * It is recommended to use it with Grafana-UI's `TagList` component. + */ +export const Tags: StoryFn = (args) => { + return ( + + Test dashboard + Card with a list of tags - console.log('tag', tag)} /> + console.log(tag)} /> ); }; -export const WithMedia: StoryFn = (args) => { +/** + * Card can be used as a clickable link item by specifying `href` prop. + */ +export const AsALink: StoryFn = (args) => { return ( - - 1-ops-tools1-fallback - - Prometheus - - https://ops-us-east4.grafana.net/api/prom - - - - Prometheus Logo - + + Redirect to Grafana + Clicking this card will redirect to grafana website ); }; -export const WithActions: StoryFn = (args) => { + +/** + * Card can be used as a clickable buttons item by specifying `onClick` prop. + * **Note:** When used in conjunction with [Metadata elements](#multiple-metadata-elements), clicking on any element + * inside `` will prevent the card action to be executed (either `href` to be followed or `onClick` to be called). + */ +export const AsAButton: StoryFn = (args) => { + return ( + alert('Hello, Grafana!')}> + Hello, Grafana + Clicking this card will create an alert + + ); +}; + +/** + * To render cards in a list, it is possible to nest them inside `li` items. + */ +export const InsideAListItem: StoryFn = (args) => { + return ( +
    +
  • + + List card item + Card that is rendered inside li element. + +
  • +
  • + + List card item + Card that is rendered inside li element. + +
  • +
  • + + List card item + Card that is rendered inside li element. + +
  • +
  • + + List card item + Card that is rendered inside li element. + +
  • +
+ ); +}; + +/** + * Cards can also be rendered with media content such icons or images. Such elements need to be wrapped in `Card.Figure` component. + */ +export const WithMediaElements: StoryFn = (args) => { + return ( + + 1-ops-tools1-fallback + + Grafana Logo + + + Grafana + + https://ops-us-east4.grafana.net/api/prom + + + + ); +}; + +/** + * Cards also accept primary and secondary actions. Usually the primary actions are displayed as buttons + * while secondary actions are displayed as icon buttons. The actions need to be wrapped in `Card.Actions` + * and `Card.SecondaryActions` components respectively. + */ +export const ActionCards: StoryFn = (args) => { return ( 1-ops-tools1-fallback @@ -118,6 +215,51 @@ export const WithActions: StoryFn = (args) => { ); }; +/** + * Card can have a disabled state, effectively making it and its actions non-clickable. + * If there are any actions, they will be disabled instead of the whole card. + */ +export const DisabledState: StoryFn = (args) => { + return ( + + 1-ops-tools1-fallback + + Grafana + + https://ops-us-east4.grafana.net/api/prom + + + + Grafana Logo + + + + + + + + + + + ); +}; + +export const Selectable: StoryFn = () => { + return ( + + Option #1 + This is a really great option, you will not regret it. + + Grafana Logo + + + ); +}; + export const Full: StoryFn = (args) => { return ( @@ -155,28 +297,4 @@ export const Full: StoryFn = (args) => { ); }; -export const Selected: StoryFn = () => { - return ( - - Spaces - Spaces are the superior form of indenting code. - - Grafana Logo - - - ); -}; - -export const NotSelected: StoryFn = () => { - return ( - - Tabs - Tabs are the preferred way of indentation. - - Grafana Logo - - - ); -}; - export default meta;