From 66929530b1622c709d8aa9efea792eee644efea6 Mon Sep 17 00:00:00 2001 From: Katerina Skroumpelou Date: Fri, 19 Jan 2024 00:34:54 +0200 Subject: [PATCH] feat(graph): hover to see source & more UI updates (#21182) Co-authored-by: Jack Hsu --- graph/project-details/jest.config.ts | 11 + graph/project-details/project.json | 7 + .../src/lib/get-source-information.ts | 16 - .../src/lib/project-details.tsx | 4 +- .../src/lib/property-renderer.tsx | 125 ----- graph/project-details/src/lib/target.spec.tsx | 10 - graph/project-details/src/lib/target.tsx | 234 ---------- .../src/lib/target/copy-to-clipboard.tsx | 31 ++ .../fading-collapsible.tsx} | 0 .../src/lib/target/source-info.tsx | 7 + .../target/target-configuration-details.tsx | 440 ++++++++++++++++++ .../target-configuration-details.util.spec.ts | 26 ++ .../target-configuration-details.util.ts | 21 + .../target/target-configuration-property.tsx | 44 ++ graph/project-details/tsconfig.json | 3 + graph/project-details/tsconfig.spec.json | 20 + graph/ui-code-block/.storybook/main.ts | 21 + graph/ui-code-block/.storybook/preview.ts | 1 + graph/ui-code-block/.storybook/tailwind.css | 3 + graph/ui-code-block/postcss.config.js | 9 + graph/ui-code-block/project.json | 43 ++ .../src/lib/json-code-block.stories.tsx | 20 + .../ui-code-block/src/lib/json-code-block.tsx | 62 ++- graph/ui-code-block/tailwind.config.js | 45 ++ graph/ui-code-block/tsconfig.json | 3 + graph/ui-code-block/tsconfig.lib.json | 7 +- graph/ui-code-block/tsconfig.storybook.json | 31 ++ package.json | 2 + pnpm-lock.yaml | 354 ++++++++------ 29 files changed, 1065 insertions(+), 535 deletions(-) create mode 100644 graph/project-details/jest.config.ts delete mode 100644 graph/project-details/src/lib/get-source-information.ts delete mode 100644 graph/project-details/src/lib/property-renderer.tsx delete mode 100644 graph/project-details/src/lib/target.spec.tsx delete mode 100644 graph/project-details/src/lib/target.tsx create mode 100644 graph/project-details/src/lib/target/copy-to-clipboard.tsx rename graph/project-details/src/lib/{ui/fading-collapsible.component.tsx => target/fading-collapsible.tsx} (100%) create mode 100644 graph/project-details/src/lib/target/source-info.tsx create mode 100644 graph/project-details/src/lib/target/target-configuration-details.tsx create mode 100644 graph/project-details/src/lib/target/target-configuration-details.util.spec.ts create mode 100644 graph/project-details/src/lib/target/target-configuration-details.util.ts create mode 100644 graph/project-details/src/lib/target/target-configuration-property.tsx create mode 100644 graph/project-details/tsconfig.spec.json create mode 100644 graph/ui-code-block/.storybook/main.ts create mode 100644 graph/ui-code-block/.storybook/preview.ts create mode 100644 graph/ui-code-block/.storybook/tailwind.css create mode 100644 graph/ui-code-block/postcss.config.js create mode 100644 graph/ui-code-block/src/lib/json-code-block.stories.tsx create mode 100644 graph/ui-code-block/tailwind.config.js create mode 100644 graph/ui-code-block/tsconfig.storybook.json diff --git a/graph/project-details/jest.config.ts b/graph/project-details/jest.config.ts new file mode 100644 index 0000000000..ff5ea94fea --- /dev/null +++ b/graph/project-details/jest.config.ts @@ -0,0 +1,11 @@ +/* eslint-disable */ +export default { + testEnvironment: 'jsdom', + displayName: 'graph-project-details', + preset: '../../jest.preset.js', + transform: { + '^.+\\.[tj]sx?$': 'babel-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../coverage/graph/project-details', +}; diff --git a/graph/project-details/project.json b/graph/project-details/project.json index 5a87e5aa7a..9560c8882c 100644 --- a/graph/project-details/project.json +++ b/graph/project-details/project.json @@ -8,6 +8,13 @@ "lint": { "executor": "@nx/eslint:lint", "outputs": ["{options.outputFile}"] + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "graph/project-details/jest.config.ts" + } } } } diff --git a/graph/project-details/src/lib/get-source-information.ts b/graph/project-details/src/lib/get-source-information.ts deleted file mode 100644 index 9a57d936cc..0000000000 --- a/graph/project-details/src/lib/get-source-information.ts +++ /dev/null @@ -1,16 +0,0 @@ -export function getSourceInformation( - sourceMap: Record, - key: string -): string | undefined { - const sourceInfo = sourceMap?.[key]; - if (sourceInfo) { - return `${key} was set by plugin \n \n ${sourceInfo[1]} \n \n while processing \n \n ${sourceInfo[0]}`; - } - if (!key.includes('.')) { - return undefined; - } - return getSourceInformation( - sourceMap, - key.substring(0, key.lastIndexOf('.')) - ); -} diff --git a/graph/project-details/src/lib/project-details.tsx b/graph/project-details/src/lib/project-details.tsx index 42e8affe7c..03c5f913d3 100644 --- a/graph/project-details/src/lib/project-details.tsx +++ b/graph/project-details/src/lib/project-details.tsx @@ -12,7 +12,7 @@ import { useEnvironmentConfig, useRouteConstructor, } from '@nx/graph/shared'; -import Target from './target'; +import { TargetConfigurationDetails } from './target/target-configuration-details'; export interface ProjectDetailsProps { project: ProjectGraphProjectNode; @@ -89,7 +89,7 @@ export function ProjectDetails({ }; return (
  • - +
  • ); } diff --git a/graph/project-details/src/lib/property-renderer.tsx b/graph/project-details/src/lib/property-renderer.tsx deleted file mode 100644 index 6da74f2105..0000000000 --- a/graph/project-details/src/lib/property-renderer.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { getSourceInformation } from './get-source-information'; -import { useState } from 'react'; - -/* eslint-disable-next-line */ -export interface PropertyRendererProps { - propertyKey: string; - propertyValue: any; - keyPrefix?: string; - sourceMap: Record; -} - -export function PropertyRenderer(props: PropertyRendererProps) { - const { propertyValue, propertyKey, sourceMap, keyPrefix } = props; - const sourceMapKey = `${keyPrefix ? `${keyPrefix}.` : ''}${propertyKey}`; - const isCollapsible = propertyValue && typeof propertyValue === 'object'; - const [isCollapsed, setIsCollapsed] = useState(true); - - const toggleCollapse = () => { - setIsCollapsed(!isCollapsed); - }; - - return ( -
    - - {isCollapsible && ( - - )} - - {propertyKey} -
    -
    - : {renderOpening(propertyValue)} -
    - - {!isCollapsed || !isCollapsible ? ( - - ) : ( - '...' - )} - {renderClosing(propertyValue)} -
    - ); -} - -type PropertValueRendererProps = PropertyRendererProps & { - nested?: boolean; -}; - -function PropertyValueRenderer(props: PropertValueRendererProps) { - const { propertyKey, propertyValue, sourceMap, keyPrefix, nested } = props; - - if (propertyValue && Array.isArray(propertyValue) && propertyValue.length) { - return ( -
    - {nested && renderOpening(propertyValue)} - {propertyValue.map((v) => - PropertyValueRenderer({ - propertyKey, - propertyValue: v, - sourceMap, - keyPrefix: `${keyPrefix ? `${keyPrefix}.` : ''}${v}`, - nested: true, - }) - )} - {nested && renderClosing(propertyValue)} -
    - ); - } else if (propertyValue && typeof propertyValue === 'object') { - return ( -
    - {nested && renderOpening(propertyValue)} -
    - {Object.entries(propertyValue) - .filter( - ([, value]) => - value && (Array.isArray(value) ? value.length : true) - ) - .map(([key, value]) => - PropertyRenderer({ - propertyKey: key, - propertyValue: value, - keyPrefix: `${keyPrefix ? `${keyPrefix}.` : ''}${propertyKey}`, - sourceMap, - }) - )} -
    - {nested && renderClosing(propertyValue)} -
    - ); - } else { - return ( - <> - {`${propertyValue}`}, - - ); - } -} - -function renderOpening(value: any): string { - return value && Array.isArray(value) && value.length - ? '[' - : value && typeof value === 'object' - ? '{' - : ''; -} - -function renderClosing(value: any): string { - return value && Array.isArray(value) && value.length - ? '],' - : value && typeof value === 'object' - ? '},' - : ''; -} - -export default PropertyRenderer; diff --git a/graph/project-details/src/lib/target.spec.tsx b/graph/project-details/src/lib/target.spec.tsx deleted file mode 100644 index d85ce6d500..0000000000 --- a/graph/project-details/src/lib/target.spec.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { render } from '@testing-library/react'; - -import Target from './target'; - -describe('Target', () => { - it('should render successfully', () => { - const { baseElement } = render(); - expect(baseElement).toBeTruthy(); - }); -}); diff --git a/graph/project-details/src/lib/target.tsx b/graph/project-details/src/lib/target.tsx deleted file mode 100644 index 06707c8f67..0000000000 --- a/graph/project-details/src/lib/target.tsx +++ /dev/null @@ -1,234 +0,0 @@ -/* eslint-disable @nx/enforce-module-boundaries */ -// nx-ignore-next-line -import { - ChevronDownIcon, - ChevronUpIcon, - EyeIcon, - PlayIcon, -} from '@heroicons/react/24/outline'; - -// nx-ignore-next-line -import { TargetConfiguration } from '@nx/devkit'; -import { - getExternalApiService, - useEnvironmentConfig, - useRouteConstructor, -} from '@nx/graph/shared'; -import { JsonCodeBlock } from '@nx/graph/ui-code-block'; -import { useEffect, useState } from 'react'; -import { useNavigate, useSearchParams } from 'react-router-dom'; -import { FadingCollapsible } from './ui/fading-collapsible.component'; - -/* eslint-disable-next-line */ -export interface TargetProps { - projectName: string; - targetName: string; - targetConfiguration: TargetConfiguration; - sourceMap: Record; -} - -export function Target({ - projectName, - targetName, - targetConfiguration, - sourceMap, -}: TargetProps) { - const environment = useEnvironmentConfig()?.environment; - const externalApiService = getExternalApiService(); - const navigate = useNavigate(); - const routeContructor = useRouteConstructor(); - - const [searchParams, setSearchParams] = useSearchParams(); - const [collapsed, setCollapsed] = useState(true); - - useEffect(() => { - const expandedSections = searchParams.get('expanded')?.split(',') || []; - setCollapsed(!expandedSections.includes(targetName)); - }, [searchParams, targetName]); - - function toggleCollapsed() { - setCollapsed((prevState) => { - const newState = !prevState; - setSearchParams((currentSearchParams) => { - const expandedSections = - currentSearchParams.get('expanded')?.split(',') || []; - if (newState) { - const newExpandedSections = expandedSections.filter( - (section) => section !== targetName - ); - updateSearchParams(currentSearchParams, newExpandedSections); - } else { - if (!expandedSections.includes(targetName)) { - expandedSections.push(targetName); - updateSearchParams(currentSearchParams, expandedSections); - } - } - return currentSearchParams; - }); - - return newState; - }); - } - - function updateSearchParams(params: URLSearchParams, sections: string[]) { - if (sections.length === 0) { - params.delete('expanded'); - } else { - params.set('expanded', sections.join(',')); - } - } - - const runTarget = () => { - externalApiService.postEvent({ - type: 'run-task', - payload: { taskId: `${projectName}:${targetName}` }, - }); - }; - - const viewInTaskGraph = () => { - if (environment === 'nx-console') { - externalApiService.postEvent({ - type: 'open-task-graph', - payload: { - projectName: projectName, - targetName: targetName, - }, - }); - } else { - navigate( - routeContructor( - { - pathname: `/tasks/${encodeURIComponent(targetName)}`, - search: `?projects=${encodeURIComponent(projectName)}`, - }, - true - ) - ); - } - }; - - const shouldRenderOptions = - targetConfiguration.options && - (typeof targetConfiguration.options === 'object' - ? Object.keys(targetConfiguration.options).length - : true); - - const shouldRenderConfigurations = - targetConfiguration.configurations && - (typeof targetConfiguration.configurations === 'object' - ? Object.keys(targetConfiguration.configurations).length - : true); - - return ( -
    -
    -

    {targetName}

    -

    - {targetConfiguration?.command ?? - targetConfiguration.options?.command ?? - targetConfiguration.executor} -

    - {targetConfiguration.cache && ( - - Cacheable - - )} - - - {environment === 'nx-console' && ( - - )} - {collapsed ? ( - - ) : ( - - )} - -
    - {/* body */} - {!collapsed && ( -
    - {targetConfiguration.inputs && ( - <> -

    Inputs

    -
      - {targetConfiguration.inputs.map((input) => ( -
    • {input.toString()}
    • - ))} -
    - - )} - {targetConfiguration.outputs && ( - <> -

    Outputs

    -
      - {targetConfiguration.outputs?.map((output) => ( -
    • {output.toString()}
    • - )) ?? no outputs} -
    - - )} - {targetConfiguration.dependsOn && ( - <> -

    Depends On

    -
      - {targetConfiguration.dependsOn.map((dep) => ( -
    • {dep.toString()}
    • - ))} -
    - - )} - {shouldRenderOptions ? ( - <> -

    Options

    -
    - - - {JSON.stringify(targetConfiguration.options, null, 2)} - - -
    - - ) : ( - '' - )} - {shouldRenderConfigurations ? ( - <> -

    - Configurations{' '} - {targetConfiguration.defaultConfiguration && ( - - {targetConfiguration.defaultConfiguration} - - )} -

    - - - {JSON.stringify(targetConfiguration.configurations, null, 2)} - - - - ) : ( - '' - )} -
    - )} -
    - ); -} - -export default Target; diff --git a/graph/project-details/src/lib/target/copy-to-clipboard.tsx b/graph/project-details/src/lib/target/copy-to-clipboard.tsx new file mode 100644 index 0000000000..c4ce71d3f4 --- /dev/null +++ b/graph/project-details/src/lib/target/copy-to-clipboard.tsx @@ -0,0 +1,31 @@ +import { ClipboardIcon } from '@heroicons/react/24/outline'; +import { JSX, useEffect, useState } from 'react'; + +interface CopyToClipboardProps { + onCopy: () => void; +} + +export function CopyToClipboard(props: CopyToClipboardProps): JSX.Element { + const [copied, setCopied] = useState(false); + useEffect(() => { + if (copied) { + const timeout = setTimeout(() => { + setCopied(false); + }, 3000); + return () => clearTimeout(timeout); + } + }); + return ( + { + e.stopPropagation(); + setCopied(true); + props.onCopy(); + }} + > + ); +} diff --git a/graph/project-details/src/lib/ui/fading-collapsible.component.tsx b/graph/project-details/src/lib/target/fading-collapsible.tsx similarity index 100% rename from graph/project-details/src/lib/ui/fading-collapsible.component.tsx rename to graph/project-details/src/lib/target/fading-collapsible.tsx diff --git a/graph/project-details/src/lib/target/source-info.tsx b/graph/project-details/src/lib/target/source-info.tsx new file mode 100644 index 0000000000..322b1243ec --- /dev/null +++ b/graph/project-details/src/lib/target/source-info.tsx @@ -0,0 +1,7 @@ +export function SourceInfo(props: { data: Array }) { + return ( + + Created by {props.data[1]} from {props.data[0]} + + ); +} diff --git a/graph/project-details/src/lib/target/target-configuration-details.tsx b/graph/project-details/src/lib/target/target-configuration-details.tsx new file mode 100644 index 0000000000..c6bb275eb1 --- /dev/null +++ b/graph/project-details/src/lib/target/target-configuration-details.tsx @@ -0,0 +1,440 @@ +/* eslint-disable @nx/enforce-module-boundaries */ +// nx-ignore-next-line +import { + ChevronDownIcon, + ChevronUpIcon, + EyeIcon, + PlayIcon, +} from '@heroicons/react/24/outline'; + +// nx-ignore-next-line +import { TargetConfiguration } from '@nx/devkit'; +import { + getExternalApiService, + useEnvironmentConfig, + useRouteConstructor, +} from '@nx/graph/shared'; +import { JsonCodeBlock } from '@nx/graph/ui-code-block'; +import { useEffect, useMemo, useState } from 'react'; +import { useNavigate, useSearchParams } from 'react-router-dom'; +import { SourceInfo } from './source-info'; +import { FadingCollapsible } from './fading-collapsible'; +import { TargetConfigurationProperty } from './target-configuration-property'; +import { selectSourceInfo } from './target-configuration-details.util'; +import { CopyToClipboard } from './copy-to-clipboard'; + +/* eslint-disable-next-line */ +export interface TargetProps { + projectName: string; + targetName: string; + targetConfiguration: TargetConfiguration; + sourceMap: Record; +} + +export function TargetConfigurationDetails({ + projectName, + targetName, + targetConfiguration, + sourceMap, +}: TargetProps) { + const environment = useEnvironmentConfig()?.environment; + const externalApiService = getExternalApiService(); + const navigate = useNavigate(); + const routeContructor = useRouteConstructor(); + const [searchParams, setSearchParams] = useSearchParams(); + const [collapsed, setCollapsed] = useState(true); + + let executorLink: string | null = null; + + // TODO: Handle this better because this will not work with labs + if (targetConfiguration.executor?.startsWith('@nx/')) { + const packageName = targetConfiguration.executor + .split('/')[1] + .split(':')[0]; + const executorName = targetConfiguration.executor + .split('/')[1] + .split(':')[1]; + executorLink = `https://nx.dev/nx-api/${packageName}/executors/${executorName}`; + } else if (targetConfiguration.executor === 'nx:run-commands') { + executorLink = `https://nx.dev/nx-api/nx/executors/run-commands`; + } else if (targetConfiguration.executor === 'nx:run-script') { + executorLink = `https://nx.dev/nx-api/nx/executors/run-script`; + } + + useEffect(() => { + const expandedSections = searchParams.get('expanded')?.split(',') || []; + setCollapsed(!expandedSections.includes(targetName)); + }, [searchParams, targetName]); + + const handleCopyClick = (copyText: string) => { + navigator.clipboard.writeText(copyText); + }; + + function toggleCollapsed() { + setCollapsed((prevState) => { + const newState = !prevState; + setSearchParams((currentSearchParams) => { + const expandedSections = + currentSearchParams.get('expanded')?.split(',') || []; + if (newState) { + const newExpandedSections = expandedSections.filter( + (section) => section !== targetName + ); + updateSearchParams(currentSearchParams, newExpandedSections); + } else { + if (!expandedSections.includes(targetName)) { + expandedSections.push(targetName); + updateSearchParams(currentSearchParams, expandedSections); + } + } + return currentSearchParams; + }); + + return newState; + }); + } + + function updateSearchParams(params: URLSearchParams, sections: string[]) { + if (sections.length === 0) { + params.delete('expanded'); + } else { + params.set('expanded', sections.join(',')); + } + } + + const runTarget = () => { + externalApiService.postEvent({ + type: 'run-task', + payload: { taskId: `${projectName}:${targetName}` }, + }); + }; + + const viewInTaskGraph = () => { + if (environment === 'nx-console') { + externalApiService.postEvent({ + type: 'open-task-graph', + payload: { + projectName: projectName, + targetName: targetName, + }, + }); + } else { + navigate( + routeContructor( + { + pathname: `/tasks/${encodeURIComponent(targetName)}`, + search: `?projects=${encodeURIComponent(projectName)}`, + }, + true + ) + ); + } + }; + + const singleCommand = + targetConfiguration.executor === 'nx:run-commands' + ? targetConfiguration.command ?? targetConfiguration.options?.command + : null; + const options = useMemo(() => { + if (singleCommand) { + const { command, ...rest } = targetConfiguration.options; + return rest; + } else { + return targetConfiguration.options; + } + }, [targetConfiguration.options, singleCommand]); + + const configurations = targetConfiguration.configurations; + + const shouldRenderOptions = + options && + (typeof options === 'object' ? Object.keys(options).length : true); + + const shouldRenderConfigurations = + configurations && + (typeof configurations === 'object' + ? Object.keys(configurations).length + : true); + + return ( +
    +
    +
    +
    +

    {targetName}

    + {collapsed && ( +

    + {singleCommand ? singleCommand : targetConfiguration.executor} +

    + )} +
    +
    + { + e.stopPropagation(); + viewInTaskGraph(); + }} + /> + {targetConfiguration.cache && ( + + Cacheable + + )} + {environment === 'nx-console' && ( + { + e.stopPropagation(); + runTarget(); + }} + /> + )} + {collapsed ? ( + + ) : ( + + )} +
    +
    + {!collapsed && ( +
    + + + + + nx run {projectName}:{targetName} + + + + handleCopyClick(`nx run ${projectName}:${targetName}`) + } + /> + +
    + )} +
    + {/* body */} + {!collapsed && ( +
    +
    +

    + {singleCommand ? ( + <> + Command + + + handleCopyClick(`"command": "${singleCommand}"`) + } + /> + + + ) : ( + 'Executor' + )} +

    +

    + {executorLink ? ( + + {singleCommand ? singleCommand : targetConfiguration.executor} + + ) : singleCommand ? ( + singleCommand + ) : ( + targetConfiguration.executor + )} +

    +
    + + {targetConfiguration.inputs && ( +
    +

    + Inputs + + + handleCopyClick( + `"inputs": JSON.stringify(targetConfiguration.inputs)` + ) + } + /> + +

    +
      + {targetConfiguration.inputs.map((input) => { + const sourceInfo = selectSourceInfo( + sourceMap, + `targets.${targetName}.inputs` + ); + return ( +
    • + + {sourceInfo && ( + + + + )} + +
    • + ); + })} +
    +
    + )} + {targetConfiguration.outputs && ( +
    +

    + Outputs + + + handleCopyClick( + `"ouputs": ${JSON.stringify( + targetConfiguration.outputs + )}` + ) + } + /> + +

    +
      + {targetConfiguration.outputs?.map((output) => { + const sourceInfo = selectSourceInfo( + sourceMap, + `targets.${targetName}.outputs` + ); + return ( +
    • + + {sourceInfo && ( + + + + )} + +
    • + ); + }) ?? no outputs} +
    +
    + )} + {targetConfiguration.dependsOn && ( +
    +

    + Depends On + + + handleCopyClick( + `"dependsOn": ${JSON.stringify( + targetConfiguration.dependsOn + )}` + ) + } + /> + +

    +
      + {targetConfiguration.dependsOn.map((dep) => { + const sourceInfo = selectSourceInfo( + sourceMap, + `targets.${targetName}.dependsOn` + ); + + return ( +
    • + + + {sourceInfo && } + + +
    • + ); + })} +
    +
    + )} + + {shouldRenderOptions ? ( + <> +

    Options

    +
    + + { + const sourceInfo = selectSourceInfo( + sourceMap, + `targets.${targetName}.options.${propertyName}` + ); + return sourceInfo ? ( + + + + ) : null; + }} + /> + +
    + + ) : ( + '' + )} + + {shouldRenderConfigurations ? ( + <> +

    + Configurations{' '} + {targetConfiguration.defaultConfiguration && ( + + {targetConfiguration.defaultConfiguration} + + )} +

    + + { + const sourceInfo = selectSourceInfo( + sourceMap, + `targets.${targetName}.configurations.${propertyName}` + ); + return sourceInfo ? ( + + {' '} + + ) : null; + }} + /> + + + ) : ( + '' + )} +
    + )} +
    + ); +} + +export default TargetConfigurationDetails; diff --git a/graph/project-details/src/lib/target/target-configuration-details.util.spec.ts b/graph/project-details/src/lib/target/target-configuration-details.util.spec.ts new file mode 100644 index 0000000000..07c37737a8 --- /dev/null +++ b/graph/project-details/src/lib/target/target-configuration-details.util.spec.ts @@ -0,0 +1,26 @@ +import { selectSourceInfo } from './target-configuration-details.util'; + +test('selectSourceInfo', () => { + const map = { + targets: ['a', 'b'], + 'targets.build': ['c', 'd'], + 'targets.build.options.command': ['e', 'f'], + }; + + expect(selectSourceInfo(map, 'targets')).toEqual(['a', 'b']); + expect(selectSourceInfo(map, 'targets.build')).toEqual(['c', 'd']); + expect(selectSourceInfo(map, 'targets.build.options.command')).toEqual([ + 'e', + 'f', + ]); + // fallback to `targets.build` + expect(selectSourceInfo(map, 'targets.build.options.cwd')).toEqual([ + 'c', + 'd', + ]); + // fallback to `targets` + expect(selectSourceInfo(map, 'targets.echo.options.command')).toEqual([ + 'a', + 'b', + ]); +}); diff --git a/graph/project-details/src/lib/target/target-configuration-details.util.ts b/graph/project-details/src/lib/target/target-configuration-details.util.ts new file mode 100644 index 0000000000..268c7337c7 --- /dev/null +++ b/graph/project-details/src/lib/target/target-configuration-details.util.ts @@ -0,0 +1,21 @@ +export function selectSourceInfo( + sourceMap: Record>, + path: string +): Array | null { + let rootKey: string | undefined; + let rootSource: Array | undefined; + for (const [key, value] of Object.entries(sourceMap)) { + if (path === key) { + return value; + } else if (path.startsWith(`${key}.`)) { + // When the key is a prefix of the filter, we can record it as the root source. + // Use the most specific key for the root "." source value. + // e.g. `targets.build` takes precedence over `targets` + if (!rootKey || key.startsWith(rootKey)) { + rootKey = key; + rootSource = value; + } + } + } + return rootSource || null; +} diff --git a/graph/project-details/src/lib/target/target-configuration-property.tsx b/graph/project-details/src/lib/target/target-configuration-property.tsx new file mode 100644 index 0000000000..86e709a8b9 --- /dev/null +++ b/graph/project-details/src/lib/target/target-configuration-property.tsx @@ -0,0 +1,44 @@ +import { JSX, ReactNode } from 'react'; + +interface RenderPropertyProps { + data: string | Record | any[]; + children?: ReactNode; +} + +export function TargetConfigurationProperty({ + data, + children, +}: RenderPropertyProps): JSX.Element | null { + if (typeof data === 'string') { + return ( + + {data} + {children} + + ); + } else if (Array.isArray(data)) { + return ( +
      + {data.map((item, index) => ( +
    • + {String(item)} + {children} +
    • + ))} +
    + ); + } else if (typeof data === 'object') { + return ( +
      + {Object.entries(data).map(([key, value], index) => ( +
    • + {key}: {String(value)} + {children} +
    • + ))} +
    + ); + } else { + return null; + } +} diff --git a/graph/project-details/tsconfig.json b/graph/project-details/tsconfig.json index 95cfeb243d..3c41f10fb2 100644 --- a/graph/project-details/tsconfig.json +++ b/graph/project-details/tsconfig.json @@ -11,6 +11,9 @@ "references": [ { "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" } ], "extends": "../../tsconfig.base.json" diff --git a/graph/project-details/tsconfig.spec.json b/graph/project-details/tsconfig.spec.json new file mode 100644 index 0000000000..26ef046ac5 --- /dev/null +++ b/graph/project-details/tsconfig.spec.json @@ -0,0 +1,20 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "jest.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/graph/ui-code-block/.storybook/main.ts b/graph/ui-code-block/.storybook/main.ts new file mode 100644 index 0000000000..dfca182122 --- /dev/null +++ b/graph/ui-code-block/.storybook/main.ts @@ -0,0 +1,21 @@ +/* eslint-disable @nx/enforce-module-boundaries */ +import type { StorybookConfig } from '@storybook/react-vite'; +import { mergeConfig } from 'vite'; +// nx-ignore-next-line +import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; + +const config: StorybookConfig = { + stories: ['../src/lib/**/*.stories.@(js|jsx|ts|tsx|mdx)'], + addons: ['@storybook/addon-essentials', '@storybook/addon-interactions'], + framework: { + name: '@storybook/react-vite', + options: {}, + }, + + viteFinal: async (config) => + mergeConfig(config, { + plugins: [nxViteTsPaths()], + }), +}; + +export default config; diff --git a/graph/ui-code-block/.storybook/preview.ts b/graph/ui-code-block/.storybook/preview.ts new file mode 100644 index 0000000000..195b052493 --- /dev/null +++ b/graph/ui-code-block/.storybook/preview.ts @@ -0,0 +1 @@ +import './tailwind.css'; diff --git a/graph/ui-code-block/.storybook/tailwind.css b/graph/ui-code-block/.storybook/tailwind.css new file mode 100644 index 0000000000..23d597fe51 --- /dev/null +++ b/graph/ui-code-block/.storybook/tailwind.css @@ -0,0 +1,3 @@ +@tailwind components; +@tailwind base; +@tailwind utilities; diff --git a/graph/ui-code-block/postcss.config.js b/graph/ui-code-block/postcss.config.js new file mode 100644 index 0000000000..cc1b086df2 --- /dev/null +++ b/graph/ui-code-block/postcss.config.js @@ -0,0 +1,9 @@ +const { join } = require('path'); +module.exports = { + plugins: { + tailwindcss: { + config: join(__dirname, 'tailwind.config.js'), + }, + autoprefixer: {}, + }, +}; diff --git a/graph/ui-code-block/project.json b/graph/ui-code-block/project.json index 1115c54748..ef0c8d570f 100644 --- a/graph/ui-code-block/project.json +++ b/graph/ui-code-block/project.json @@ -14,6 +14,49 @@ "options": { "jestConfig": "graph/ui-code-block/jest.config.ts" } + }, + "storybook": { + "executor": "@nx/storybook:storybook", + "options": { + "port": 4400, + "configDir": "graph/ui-code-block/.storybook" + }, + "configurations": { + "ci": { + "quiet": true + } + } + }, + "build-storybook": { + "executor": "@nx/storybook:build", + "outputs": ["{options.outputDir}"], + "options": { + "outputDir": "dist/storybook/graph-ui-code-block", + "configDir": "graph/ui-code-block/.storybook" + }, + "configurations": { + "ci": { + "quiet": true + } + } + }, + "test-storybook": { + "executor": "nx:run-commands", + "options": { + "command": "test-storybook -c graph/ui-code-block/.storybook --url=http://localhost:4400" + } + }, + "static-storybook": { + "executor": "@nx/web:file-server", + "options": { + "buildTarget": "graph-ui-code-block:build-storybook", + "staticFilePath": "dist/storybook/graph-ui-code-block" + }, + "configurations": { + "ci": { + "buildTarget": "graph-ui-code-block:build-storybook:ci" + } + } } } } diff --git a/graph/ui-code-block/src/lib/json-code-block.stories.tsx b/graph/ui-code-block/src/lib/json-code-block.stories.tsx new file mode 100644 index 0000000000..1683789935 --- /dev/null +++ b/graph/ui-code-block/src/lib/json-code-block.stories.tsx @@ -0,0 +1,20 @@ +import type { Meta, StoryObj } from '@storybook/react'; +import { JsonCodeBlock } from './json-code-block'; + +const meta: Meta = { + component: JsonCodeBlock, + title: 'JsonCodeBlock', +}; +export default meta; + +type Story = StoryObj; + +export const Simple: Story = { + args: { + data: { + commands: [{ command: 'remix build' }], + cwd: 'apps/demo', + }, + renderSource: (propertyName: string) => test, + }, +}; diff --git a/graph/ui-code-block/src/lib/json-code-block.tsx b/graph/ui-code-block/src/lib/json-code-block.tsx index 140bf07d59..0e5939f177 100644 --- a/graph/ui-code-block/src/lib/json-code-block.tsx +++ b/graph/ui-code-block/src/lib/json-code-block.tsx @@ -1,14 +1,12 @@ import { ClipboardDocumentCheckIcon, ClipboardDocumentIcon, - InformationCircleIcon, - SparklesIcon, } from '@heroicons/react/24/outline'; // @ts-ignore import { CopyToClipboard } from 'react-copy-to-clipboard'; // @ts-ignore -import SyntaxHighlighter from 'react-syntax-highlighter'; -import { Children, JSX, ReactNode, useEffect, useState } from 'react'; +import SyntaxHighlighter, { createElement } from 'react-syntax-highlighter'; +import { JSX, ReactNode, useEffect, useMemo, useState } from 'react'; import { twMerge } from 'tailwind-merge'; export function JsonCodeBlockPreTag({ @@ -19,7 +17,7 @@ export function JsonCodeBlockPreTag({ return (
    ReactNode; +} + +export function JsonCodeBlock(props: JsonCodeBlockProps): JSX.Element { const [copied, setCopied] = useState(false); + const jsonString = useMemo( + () => JSON.stringify(props.data, null, 2), + [props.data] + ); useEffect(() => { if (!copied) return; const t = setTimeout(() => { @@ -42,7 +49,7 @@ export function JsonCodeBlock(props: { children: ReactNode }): JSX.Element {
    { setCopied(true); }} @@ -64,12 +71,47 @@ export function JsonCodeBlock(props: { children: ReactNode }): JSX.Element {
    ); } + +export function sourcesRenderer( + renderSource: (propertyName: string) => ReactNode +) { + return ({ rows, stylesheet }: any) => { + return rows.map((node: any, idx: number) => { + const element = createElement({ + node, + stylesheet, + useInlineStyles: false, + key: `code-line-${idx}`, + }); + let sourceElement: ReactNode; + const attrNode = node.children.find( + (c: any) => + c.type === 'element' && c.properties?.className?.includes('hljs-attr') + ); + if (attrNode?.children?.length) { + for (const child of attrNode.children) { + sourceElement = renderSource(child.value); // e.g. command + if (sourceElement) break; + } + } + return ( + + {element} + {sourceElement && ( + + {sourceElement} + + )} + + ); + }); + }; +} diff --git a/graph/ui-code-block/tailwind.config.js b/graph/ui-code-block/tailwind.config.js new file mode 100644 index 0000000000..18a8d985ec --- /dev/null +++ b/graph/ui-code-block/tailwind.config.js @@ -0,0 +1,45 @@ +const path = require('path'); + +// nx-ignore-next-line +const { createGlobPatternsForDependencies } = require('@nx/react/tailwind'); + +module.exports = { + content: [ + path.join(__dirname, 'src/**/*.{js,ts,jsx,tsx,html}'), + ...createGlobPatternsForDependencies(__dirname), + ], + darkMode: 'class', // or 'media' or 'class' + theme: { + extend: { + typography: { + DEFAULT: { + css: { + 'code::before': { + content: '', + }, + 'code::after': { + content: '', + }, + 'blockquote p:first-of-type::before': { + content: '', + }, + 'blockquote p:last-of-type::after': { + content: '', + }, + }, + }, + }, + }, + }, + variants: { + extend: { + translate: ['group-hover'], + }, + }, + plugins: [ + require('@tailwindcss/typography'), + require('@tailwindcss/forms')({ + strategy: 'class', + }), + ], +}; diff --git a/graph/ui-code-block/tsconfig.json b/graph/ui-code-block/tsconfig.json index 3c41f10fb2..79d9ca983d 100644 --- a/graph/ui-code-block/tsconfig.json +++ b/graph/ui-code-block/tsconfig.json @@ -14,6 +14,9 @@ }, { "path": "./tsconfig.spec.json" + }, + { + "path": "./tsconfig.storybook.json" } ], "extends": "../../tsconfig.base.json" diff --git a/graph/ui-code-block/tsconfig.lib.json b/graph/ui-code-block/tsconfig.lib.json index cfc4843293..8c1bec17db 100644 --- a/graph/ui-code-block/tsconfig.lib.json +++ b/graph/ui-code-block/tsconfig.lib.json @@ -4,7 +4,6 @@ "outDir": "../../dist/out-tsc", "types": [ "node", - "@nx/react/typings/cssmodule.d.ts", "@nx/react/typings/image.d.ts" ] @@ -18,7 +17,11 @@ "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", - "src/**/*.test.jsx" + "src/**/*.test.jsx", + "**/*.stories.ts", + "**/*.stories.js", + "**/*.stories.jsx", + "**/*.stories.tsx" ], "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] } diff --git a/graph/ui-code-block/tsconfig.storybook.json b/graph/ui-code-block/tsconfig.storybook.json new file mode 100644 index 0000000000..2da3caee12 --- /dev/null +++ b/graph/ui-code-block/tsconfig.storybook.json @@ -0,0 +1,31 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "emitDecoratorMetadata": true, + "outDir": "" + }, + "files": [ + "../../node_modules/@nx/react/typings/styled-jsx.d.ts", + "../../node_modules/@nx/react/typings/cssmodule.d.ts", + "../../node_modules/@nx/react/typings/image.d.ts" + ], + "exclude": [ + "src/**/*.spec.ts", + "src/**/*.test.ts", + "src/**/*.spec.js", + "src/**/*.test.js", + "src/**/*.spec.tsx", + "src/**/*.test.tsx", + "src/**/*.spec.jsx", + "src/**/*.test.js" + ], + "include": [ + "src/**/*.stories.ts", + "src/**/*.stories.js", + "src/**/*.stories.jsx", + "src/**/*.stories.tsx", + "src/**/*.stories.mdx", + ".storybook/*.js", + ".storybook/*.ts" + ] +} diff --git a/package.json b/package.json index 031685bdd3..a694365f2c 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "@nx/playwright": "17.3.0-beta.5", "@nx/react": "17.3.0-beta.5", "@nx/storybook": "17.3.0-beta.5", + "@nx/vite": "17.3.0-beta.5", "@nx/web": "17.3.0-beta.5", "@nx/webpack": "17.3.0-beta.5", "@phenomnomnominal/tsquery": "~5.0.1", @@ -97,6 +98,7 @@ "@storybook/addon-essentials": "7.5.3", "@storybook/core-server": "7.5.3", "@storybook/react": "7.5.3", + "@storybook/react-vite": "7.5.3", "@storybook/react-webpack5": "7.5.3", "@storybook/types": "^7.1.1", "@supabase/supabase-js": "^2.26.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2907fd2e8..13ca1638fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,9 +1,5 @@ lockfileVersion: '6.0' -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - overrides: minimist: ^1.2.6 underscore: ^1.12.1 @@ -247,7 +243,7 @@ devDependencies: version: 9.1.6(@nestjs/common@9.1.6)(@nestjs/core@9.1.6) '@nestjs/schematics': specifier: ^9.1.0 - version: 9.1.0(typescript@5.2.2) + version: 9.1.0(chokidar@3.5.3)(typescript@4.9.4) '@nestjs/swagger': specifier: ^6.0.0 version: 6.1.3(@nestjs/common@9.1.6)(@nestjs/core@9.1.6)(reflect-metadata@0.1.14) @@ -305,6 +301,9 @@ devDependencies: '@nx/storybook': specifier: 17.3.0-beta.5 version: 17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(cypress@13.0.0)(eslint@8.48.0)(js-yaml@4.1.0)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4) + '@nx/vite': + specifier: 17.3.0-beta.5 + version: 17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4)(vite@5.0.8)(vitest@1.0.4) '@nx/web': specifier: 17.3.0-beta.5 version: 17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4) @@ -365,6 +364,9 @@ devDependencies: '@storybook/react': specifier: 7.5.3 version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) + '@storybook/react-vite': + specifier: 7.5.3 + version: 7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@2.79.0)(typescript@5.2.2)(vite@5.0.8) '@storybook/react-webpack5': specifier: 7.5.3 version: 7.5.3(@babel/core@7.22.9)(@swc/core@1.3.86)(@swc/helpers@0.5.3)(esbuild@0.19.5)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(webpack-dev-server@4.11.1) @@ -583,7 +585,7 @@ devDependencies: version: 2.14.0(eslint@8.48.0) eslint-plugin-import: specifier: 2.27.5 - version: 2.27.5(@typescript-eslint/parser@6.18.1)(eslint@8.48.0) + version: 2.27.5(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-typescript@3.5.2)(eslint@8.48.0) eslint-plugin-jsx-a11y: specifier: 6.7.1 version: 6.7.1(eslint@8.48.0) @@ -5918,6 +5920,23 @@ packages: chalk: 4.1.2 dev: true + /@joshwooding/vite-plugin-react-docgen-typescript@0.3.0(typescript@5.2.2)(vite@5.0.8): + resolution: {integrity: sha512-2D6y7fNvFmsLmRt6UCOFJPvFoPMJGT0Uh1Wg0RaigUp7kdQPs6yYn8Dmx6GZkOH/NW0yMTwRz/p0SRMMRo50vA==} + peerDependencies: + typescript: '>= 4.3.x' + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + glob: 7.2.3 + glob-promise: 4.2.2(glob@7.2.3) + magic-string: 0.27.0 + react-docgen-typescript: 2.2.2(typescript@5.2.2) + typescript: 5.2.2 + vite: 5.0.8(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) + dev: true + /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} engines: {node: '>=6.0.0'} @@ -6347,20 +6366,6 @@ packages: - chokidar dev: true - /@nestjs/schematics@9.1.0(typescript@5.2.2): - resolution: {integrity: sha512-/7CyMTnPJSK9/xD9CkCqwuHPOlHVlLC2RDnbdCJ7mIO07SdbBbY14msTqtYW9VRQtsjZPLh1GTChf7ryJUImwA==} - peerDependencies: - typescript: '>=4.3.5' - dependencies: - '@angular-devkit/core': 15.2.4(chokidar@3.5.3) - '@angular-devkit/schematics': 15.2.4(chokidar@3.5.3) - jsonc-parser: 3.2.0 - pluralize: 8.0.0 - typescript: 5.2.2 - transitivePeerDependencies: - - chokidar - dev: true - /@nestjs/swagger@6.1.3(@nestjs/common@9.1.6)(@nestjs/core@9.1.6)(reflect-metadata@0.1.14): resolution: {integrity: sha512-H9C/yRgLFb5QrAt6iGrYmIX9X7Q0zXkgZaTNUATljUBra+RCWrEUbLHBcGjTAOtcIyGV/vmyCLv68YSVcZoE0Q==} peerDependencies: @@ -6953,6 +6958,25 @@ packages: - debug dev: true + /@nrwl/vite@17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4)(vite@5.0.8)(vitest@1.0.4): + resolution: {integrity: sha512-ibC2tYyRkEgmsAtPywkNA4FXwSOntMXZ2u/oNytR6z8xR0OjJZNd9dMGK9Xpz/He2LvYN2TY1bscAFt969LE7g==} + dependencies: + '@nx/vite': 17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4)(vite@5.0.8)(vitest@1.0.4) + transitivePeerDependencies: + - '@babel/traverse' + - '@swc-node/register' + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - debug + - nx + - supports-color + - typescript + - verdaccio + - vite + - vitest + dev: true + /@nrwl/web@17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4): resolution: {integrity: sha512-Xo5BVi1kaHoD+vnYQ7eVQMhqCZbeJv91X3fkQ7RkQg3q892pkBDuZlJNU6f8oHetyztnI+QaL76dWnoHoX/XHg==} dependencies: @@ -7771,6 +7795,34 @@ packages: - verdaccio dev: true + /@nx/vite@17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4)(vite@5.0.8)(vitest@1.0.4): + resolution: {integrity: sha512-XRxsenOHPZj5Rfev5mw0/6z/W3VHkGAdjOtehOZcc7UQvRJsHaSP9Nonnm0QznDoZXxqfcM75d7Z4IAHjOIR9w==} + peerDependencies: + vite: ^5.0.0 + vitest: ^1.0.0 + dependencies: + '@nrwl/vite': 17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4)(vite@5.0.8)(vitest@1.0.4) + '@nx/devkit': 17.3.0-beta.5(nx@17.3.0-beta.5) + '@nx/js': 17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4) + '@phenomnomnominal/tsquery': 5.0.1(typescript@5.2.2) + '@swc/helpers': 0.5.3 + enquirer: 2.3.6 + tsconfig-paths: 4.1.2 + vite: 5.0.8(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) + vitest: 1.0.4(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) + transitivePeerDependencies: + - '@babel/traverse' + - '@swc-node/register' + - '@swc/core' + - '@swc/wasm' + - '@types/node' + - debug + - nx + - supports-color + - typescript + - verdaccio + dev: true + /@nx/web@17.3.0-beta.5(@swc-node/register@1.6.8)(@swc/core@1.3.86)(@types/node@18.19.8)(nx@17.3.0-beta.5)(typescript@5.2.2)(verdaccio@5.15.4): resolution: {integrity: sha512-jVklzqnmjbEy+0vnlMgL2sCcAWiIwso/ZGDY8eMbFGdd7PLwMJ/RNMl8W9V34F0vBK/qcmfPcKdGinvZClgBpw==} dependencies: @@ -9208,7 +9260,7 @@ packages: rollup: optional: true dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 rollup: 2.79.0 @@ -9223,7 +9275,7 @@ packages: rollup: optional: true dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 rollup: 4.3.0 @@ -9786,6 +9838,44 @@ packages: - supports-color dev: true + /@storybook/builder-vite@7.5.3(typescript@5.2.2)(vite@5.0.8): + resolution: {integrity: sha512-c104V3O75OCVnfZj0Jr70V09g0KSbPGvQK2Zh31omXGvakG8XrhWolYxkmjOcForJmAqsXnKs/nw3F75Gp853g==} + peerDependencies: + '@preact/preset-vite': '*' + typescript: '>= 4.3.x' + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + vite-plugin-glimmerx: '*' + peerDependenciesMeta: + '@preact/preset-vite': + optional: true + typescript: + optional: true + vite-plugin-glimmerx: + optional: true + dependencies: + '@storybook/channels': 7.5.3 + '@storybook/client-logger': 7.5.3 + '@storybook/core-common': 7.5.3 + '@storybook/csf-plugin': 7.5.3 + '@storybook/node-logger': 7.5.3 + '@storybook/preview': 7.5.3 + '@storybook/preview-api': 7.5.3 + '@storybook/types': 7.5.3 + '@types/find-cache-dir': 3.2.1 + browser-assert: 1.2.1 + es-module-lexer: 0.9.3 + express: 4.18.2 + find-cache-dir: 3.3.2 + fs-extra: 11.1.1 + magic-string: 0.30.5 + rollup: 2.79.0 + typescript: 5.2.2 + vite: 5.0.8(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) + transitivePeerDependencies: + - encoding + - supports-color + dev: true + /@storybook/builder-webpack5@7.5.3(@swc/helpers@0.5.3)(esbuild@0.19.5)(typescript@5.2.2): resolution: {integrity: sha512-a2kHXFT61AV1+OPNTqXCsYk7Wk4XSqjAOQkSxWc1HK+kyMT+lahO4U06slji6XAVuXc/KY+naNUoaOfpB1hKVw==} peerDependencies: @@ -10302,6 +10392,33 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: true + /@storybook/react-vite@7.5.3(react-dom@18.2.0)(react@18.2.0)(rollup@2.79.0)(typescript@5.2.2)(vite@5.0.8): + resolution: {integrity: sha512-ArPyHgiPbT5YvcyK4xK/DfqBOpn4R4/EP3kfIGhx8QKJyOtxPEYFdkLIZ5xu3KnPX7/z7GT+4a6Rb+8sk9gliA==} + engines: {node: '>=16'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 + dependencies: + '@joshwooding/vite-plugin-react-docgen-typescript': 0.3.0(typescript@5.2.2)(vite@5.0.8) + '@rollup/pluginutils': 5.0.5(rollup@2.79.0) + '@storybook/builder-vite': 7.5.3(typescript@5.2.2)(vite@5.0.8) + '@storybook/react': 7.5.3(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2) + '@vitejs/plugin-react': 3.1.0(vite@5.0.8) + magic-string: 0.30.5 + react: 18.2.0 + react-docgen: 6.0.4 + react-dom: 18.2.0(react@18.2.0) + vite: 5.0.8(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) + transitivePeerDependencies: + - '@preact/preset-vite' + - encoding + - rollup + - supports-color + - typescript + - vite-plugin-glimmerx + dev: true + /@storybook/react-webpack5@7.5.3(@babel/core@7.22.9)(@swc/core@1.3.86)(@swc/helpers@0.5.3)(esbuild@0.19.5)(react-dom@18.2.0)(react@18.2.0)(typescript@5.2.2)(webpack-dev-server@4.11.1): resolution: {integrity: sha512-+sjYMrvmpvztdDkRE1/EkcNNxTTdDdBoXUGrGyE0ig6qEwSewRld0H8ng1jlNQ8treocy7036TXJF+qHZEz/FQ==} engines: {node: '>=16.0.0'} @@ -11005,7 +11122,7 @@ packages: /@types/acorn@4.0.6: resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 dev: true /@types/aria-query@5.0.4: @@ -11126,6 +11243,10 @@ packages: resolution: {integrity: sha512-w5jZ0ee+HaPOaX25X2/2oGR/7rgAQSYII7X7pp0m9KgBfMP7uKfMfTvcpl5Dj+eDBbpxKGiqE+flqDr6XTd2RA==} dev: true + /@types/doctrine@0.0.6: + resolution: {integrity: sha512-KlEqPtaNBHBJ2/fVA4yLdD0Tc8zw34pKU4K5SHBIEwtLJ8xxumIC1xeG+4S+/9qhVj2MqC7O3Ld8WvDG4HqlgA==} + dev: true + /@types/ejs@3.1.2: resolution: {integrity: sha512-ZmiaE3wglXVWBM9fyVC17aGPkLo/UgaOjEiI2FXQfyczrCefORPxIe+2dVmnmk3zkVIbizjrlQzmPGhSYGXG5g==} dev: true @@ -11151,7 +11272,7 @@ packages: /@types/estree-jsx@1.0.3: resolution: {integrity: sha512-pvQ+TKeRHeiUGRhvYwRrQ/ISnohKkSJR14fT2yqyZ4e9K5vqc7hrtY2Y1Dw0ZwAzQ6DQsxsaCUuSIIi8v0Cq6w==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 dev: true /@types/estree@0.0.39: @@ -11969,7 +12090,7 @@ packages: lodash: 4.17.21 mlly: 1.4.2 outdent: 0.8.0 - vite: 4.5.0(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) + vite: 4.5.0(@types/node@18.19.8)(less@4.2.0)(sass@1.69.5)(stylus@0.59.0)(terser@5.24.0) vite-node: 0.28.5(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) transitivePeerDependencies: - '@types/node' @@ -12048,6 +12169,22 @@ packages: vite: 4.5.0(@types/node@18.19.8)(less@4.2.0)(sass@1.69.5)(stylus@0.59.0)(terser@5.24.0) dev: true + /@vitejs/plugin-react@3.1.0(vite@5.0.8): + resolution: {integrity: sha512-AfgcRL8ZBhAlc3BFdigClmTUMISmmzHn7sB2h9U1odvc5U/MjWXsAaz18b/WoppUTDBzxOJwo2VdClfUcItu9g==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.1.0-beta.0 + dependencies: + '@babel/core': 7.23.2 + '@babel/plugin-transform-react-jsx-self': 7.22.5(@babel/core@7.23.2) + '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.23.2) + magic-string: 0.27.0 + react-refresh: 0.14.0 + vite: 5.0.8(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) + transitivePeerDependencies: + - supports-color + dev: true + /@vitest/expect@1.0.4: resolution: {integrity: sha512-/NRN9N88qjg3dkhmFcCBwhn/Ie4h064pY3iv7WLRsDJW7dXnEgeoa8W9zy7gIPluhz6CkgqiB3HmpIXgmEY5dQ==} dependencies: @@ -16677,35 +16814,6 @@ packages: - supports-color dev: true - /eslint-module-utils@2.7.4(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-node@0.3.9)(eslint@8.48.0): - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - '@typescript-eslint/parser': 6.18.1(eslint@8.48.0)(typescript@5.2.2) - debug: 3.2.7(supports-color@8.1.1) - eslint: 8.48.0 - eslint-import-resolver-node: 0.3.9 - transitivePeerDependencies: - - supports-color - dev: true - /eslint-plugin-cypress@2.14.0(eslint@8.48.0): resolution: {integrity: sha512-eW6tv7iIg7xujleAJX4Ujm649Bf5jweqa4ObPEIuueYRyLZt7qXGWhCY/n4bfeFW/j6nQZwbIBHKZt6EKcL/cg==} peerDependencies: @@ -16748,39 +16856,6 @@ packages: - supports-color dev: true - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@6.18.1)(eslint@8.48.0): - resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - '@typescript-eslint/parser': 6.18.1(eslint@8.48.0)(typescript@5.2.2) - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - array.prototype.flatmap: 1.3.1 - debug: 3.2.7(supports-color@8.1.1) - doctrine: 2.1.0 - eslint: 8.48.0 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@6.18.1)(eslint-import-resolver-node@0.3.9)(eslint@8.48.0) - has: 1.0.3 - is-core-module: 2.13.0 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.values: 1.1.6 - resolve: 1.22.8 - semver: 6.3.1 - tsconfig-paths: 3.14.1 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - /eslint-plugin-jsx-a11y@6.7.1(eslint@8.48.0): resolution: {integrity: sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==} engines: {node: '>=4.0'} @@ -17007,7 +17082,7 @@ packages: /estree-util-attach-comments@2.1.1: resolution: {integrity: sha512-+5Ba/xGGS6mnwFbXIuQiDPTbuTxuMCooq3arVv7gPZtYpjp+VXH/NkHAP35OOefPhNG/UGqU3vt/LTABwcHX0w==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 dev: true /estree-util-build-jsx@2.2.2: @@ -18202,6 +18277,16 @@ packages: glob: 7.2.3 dev: false + /glob-promise@4.2.2(glob@7.2.3): + resolution: {integrity: sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw==} + engines: {node: '>=12'} + peerDependencies: + glob: ^7.1.6 + dependencies: + '@types/glob': 7.2.0 + glob: 7.2.3 + dev: true + /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} dev: true @@ -18513,7 +18598,7 @@ packages: /hast-util-to-estree@2.3.3: resolution: {integrity: sha512-ihhPIUPxN0v0w6M5+IiAZZrn0LH2uZomeWwhn7uP7avZC6TE7lIiEh2yBMPr5+zi1aUCXq6VoYRgs2Bw9xmycQ==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 '@types/estree-jsx': 1.0.3 '@types/hast': 2.3.4 '@types/unist': 2.0.6 @@ -19508,7 +19593,7 @@ packages: /is-reference@3.0.1: resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 dev: true /is-reference@3.0.2: @@ -21308,6 +21393,13 @@ packages: sourcemap-codec: 1.4.8 dev: true + /magic-string@0.27.0: + resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.15 + dev: true + /magic-string@0.29.0: resolution: {integrity: sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==} engines: {node: '>=12'} @@ -22010,7 +22102,7 @@ packages: /micromark-extension-mdx-expression@1.0.8: resolution: {integrity: sha512-zZpeQtc5wfWKdzDsHRBY003H2Smg+PUi2REhqgIhdzAa5xonhP03FcXxqFSerFiNUr5AWmHpaNPQTBVOS4lrXw==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 micromark-factory-mdx-expression: 1.0.9 micromark-factory-space: 1.1.0 micromark-util-character: 1.2.0 @@ -22024,7 +22116,7 @@ packages: resolution: {integrity: sha512-gPH+9ZdmDflbu19Xkb8+gheqEDqkSpdCEubQyxuz/Hn8DOXiXvrXeikOoBA71+e8Pfi0/UYmU3wW3H58kr7akA==} dependencies: '@types/acorn': 4.0.6 - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 estree-util-is-identifier-name: 2.1.0 micromark-factory-mdx-expression: 1.0.9 micromark-factory-space: 1.1.0 @@ -22044,7 +22136,7 @@ packages: /micromark-extension-mdxjs-esm@1.0.5: resolution: {integrity: sha512-xNRBw4aoURcyz/S69B19WnZAkWJMxHMT5hE36GtDAyhoyn/8TuAeqjFJQlwk+MKQsUD7b3l7kFX+vlfVWgcX1w==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 micromark-core-commonmark: 1.1.0 micromark-util-character: 1.2.0 micromark-util-events-to-acorn: 1.2.3 @@ -22088,7 +22180,7 @@ packages: /micromark-factory-mdx-expression@1.0.9: resolution: {integrity: sha512-jGIWzSmNfdnkJq05c7b0+Wv0Kfz3NJ3N4cBjnbO4zjXIlxJr+f8lk+5ZmwFvqdAbUy2q6B5rCY//g0QAAaXDWA==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 micromark-util-character: 1.2.0 micromark-util-events-to-acorn: 1.2.3 micromark-util-symbol: 1.1.0 @@ -22174,7 +22266,7 @@ packages: resolution: {integrity: sha512-ij4X7Wuc4fED6UoLWkmo0xJQhsktfNh1J0m8g4PbIMPlx+ek/4YdW5mvbye8z/aZvAPUoxgXHrwVlXAPKMRp1w==} dependencies: '@types/acorn': 4.0.6 - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 '@types/unist': 2.0.6 estree-util-visit: 1.2.1 micromark-util-symbol: 1.1.0 @@ -23911,7 +24003,7 @@ packages: /periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} dependencies: - '@types/estree': 1.0.1 + '@types/estree': 1.0.5 estree-walker: 3.0.3 is-reference: 3.0.1 dev: true @@ -25643,6 +25735,24 @@ packages: - supports-color dev: true + /react-docgen@6.0.4: + resolution: {integrity: sha512-gF+p+1ZwC2eO66bt763Tepmh5q9kDiFIrqW3YjUV/a+L96h0m5+/wSFQoOHL2cffyrPMZMxP03IgbggJ11QbOw==} + engines: {node: '>=14.18.0'} + dependencies: + '@babel/core': 7.23.2 + '@babel/traverse': 7.23.2 + '@babel/types': 7.23.6 + '@types/babel__core': 7.20.1 + '@types/babel__traverse': 7.18.2 + '@types/doctrine': 0.0.6 + '@types/resolve': 1.20.2 + doctrine: 3.0.0 + resolve: 1.22.8 + strip-indent: 4.0.0 + transitivePeerDependencies: + - supports-color + dev: true + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -27677,6 +27787,13 @@ packages: min-indent: 1.0.1 dev: true + /strip-indent@4.0.0: + resolution: {integrity: sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==} + engines: {node: '>=12'} + dependencies: + min-indent: 1.0.1 + dev: true + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -29467,7 +29584,7 @@ packages: picocolors: 1.0.0 source-map: 0.6.1 source-map-support: 0.5.21 - vite: 4.5.0(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0) + vite: 4.5.0(@types/node@18.19.8)(less@4.2.0)(sass@1.69.5)(stylus@0.59.0)(terser@5.24.0) transitivePeerDependencies: - '@types/node' - less @@ -29500,45 +29617,6 @@ packages: - terser dev: true - /vite@4.5.0(@types/node@18.19.8)(less@4.1.3)(sass@1.55.0)(stylus@0.59.0): - resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - '@types/node': 18.19.8 - esbuild: 0.18.17 - less: 4.1.3 - postcss: 8.4.32 - rollup: 3.28.0 - sass: 1.55.0 - stylus: 0.59.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - /vite@4.5.0(@types/node@18.19.8)(less@4.2.0)(sass@1.69.5)(stylus@0.59.0)(terser@5.24.0): resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} engines: {node: ^14.18.0 || >=16.0.0} @@ -30635,3 +30713,7 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: true + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false