diff --git a/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisAnalyzedRepoItem.stories.tsx b/extensions/ql-vscode/src/stories/variant-analysis/RepoRow.stories.tsx similarity index 74% rename from extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisAnalyzedRepoItem.stories.tsx rename to extensions/ql-vscode/src/stories/variant-analysis/RepoRow.stories.tsx index c448f149a3f..b9a6ebc51dc 100644 --- a/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisAnalyzedRepoItem.stories.tsx +++ b/extensions/ql-vscode/src/stories/variant-analysis/RepoRow.stories.tsx @@ -3,16 +3,16 @@ import React from 'react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; import { VariantAnalysisContainer } from '../../view/variant-analysis/VariantAnalysisContainer'; -import { VariantAnalysisAnalyzedRepoItem } from '../../view/variant-analysis/VariantAnalysisAnalyzedRepoItem'; import { VariantAnalysisRepoStatus } from '../../remote-queries/shared/variant-analysis'; import { AnalysisAlert, AnalysisRawResults } from '../../remote-queries/shared/analysis-result'; import analysesResults from '../remote-queries/data/analysesResultsMessage.json'; import rawResults from '../remote-queries/data/rawResults.json'; +import { RepoRow } from '../../view/variant-analysis/RepoRow'; export default { - title: 'Variant Analysis/Analyzed Repo Item', - component: VariantAnalysisAnalyzedRepoItem, + title: 'Variant Analysis/Repo Row', + component: RepoRow, decorators: [ (Story) => ( @@ -20,10 +20,10 @@ export default { ) ], -} as ComponentMeta; +} as ComponentMeta; -const Template: ComponentStory = (args) => ( - +const Template: ComponentStory = (args) => ( + ); export const Pending = Template.bind({}); @@ -77,3 +77,26 @@ RawResults.args = { resultCount: 1, rawResults: rawResults as unknown as AnalysisRawResults, }; + +export const SkippedOnlyFullName = Template.bind({}); +SkippedOnlyFullName.args = { + repository: { + fullName: 'octodemo/hello-globe', + } +}; + +export const SkippedPublic = Template.bind({}); +SkippedPublic.args = { + repository: { + fullName: 'octodemo/hello-globe', + private: false, + } +}; + +export const SkippedPrivate = Template.bind({}); +SkippedPrivate.args = { + repository: { + fullName: 'octodemo/hello-globe', + private: true, + } +}; diff --git a/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisSkippedRepositoryRow.stories.tsx b/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisSkippedRepositoryRow.stories.tsx deleted file mode 100644 index 7f33d53cdad..00000000000 --- a/extensions/ql-vscode/src/stories/variant-analysis/VariantAnalysisSkippedRepositoryRow.stories.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; - -import { ComponentMeta, ComponentStory } from '@storybook/react'; - -import { VariantAnalysisContainer } from '../../view/variant-analysis/VariantAnalysisContainer'; -import { VariantAnalysisSkippedRepositoryRow } from '../../view/variant-analysis/VariantAnalysisSkippedRepositoryRow'; - -export default { - title: 'Variant Analysis/Variant Analysis Skipped Repository', - component: VariantAnalysisSkippedRepositoryRow, - decorators: [ - (Story) => ( - - - - ) - ], -} as ComponentMeta; - -const Template: ComponentStory = (args) => ( - -); - -export const OnlyFullName = Template.bind({}); -OnlyFullName.args = { - repository: { - fullName: 'octodemo/hello-globe', - } -}; - -export const Public = Template.bind({}); -Public.args = { - repository: { - fullName: 'octodemo/hello-globe', - private: false, - } -}; - -export const Private = Template.bind({}); -Private.args = { - repository: { - fullName: 'octodemo/hello-globe', - private: true, - } -}; diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisAnalyzedRepoItem.tsx b/extensions/ql-vscode/src/view/variant-analysis/RepoRow.tsx similarity index 67% rename from extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisAnalyzedRepoItem.tsx rename to extensions/ql-vscode/src/view/variant-analysis/RepoRow.tsx index ab3f056577e..148ecebfc47 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisAnalyzedRepoItem.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/RepoRow.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import { useCallback, useState } from 'react'; import styled from 'styled-components'; -import { VSCodeBadge } from '@vscode/webview-ui-toolkit/react'; +import { VSCodeBadge, VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react'; import { isCompletedAnalysisRepoStatus, VariantAnalysisRepoStatus } from '../../remote-queries/shared/variant-analysis'; import { formatDecimal } from '../../pure/number'; -import { Codicon, ErrorIcon, LoadingIcon, SuccessIcon } from '../common'; +import { Codicon, ErrorIcon, LoadingIcon, SuccessIcon, WarningIcon } from '../common'; import { Repository } from '../../remote-queries/shared/repository'; import { AnalysisAlert, AnalysisRawResults } from '../../remote-queries/shared/analysis-result'; import { AnalyzedRepoItemContent } from './AnalyzedRepoItemContent'; @@ -31,20 +31,22 @@ const TitleContainer = styled.button` } `; -const Visibility = styled.span` +const VisibilityText = styled.span` font-size: 0.85em; color: var(--vscode-descriptionForeground); `; -export type VariantAnalysisAnalyzedRepoItemProps = { - repository: Repository; - status: VariantAnalysisRepoStatus; - resultCount?: number; - - interpretedResults?: AnalysisAlert[]; - rawResults?: AnalysisRawResults; +type VisibilityProps = { + isPrivate?: boolean; } +const Visibility = ({ isPrivate }: VisibilityProps) => { + if (isPrivate === undefined) { + return null; + } + return {isPrivate ? 'private' : 'public'}; +}; + const getErrorLabel = (status: VariantAnalysisRepoStatus.Failed | VariantAnalysisRepoStatus.TimedOut | VariantAnalysisRepoStatus.Canceled): string => { switch (status) { case VariantAnalysisRepoStatus.Failed: @@ -56,35 +58,50 @@ const getErrorLabel = (status: VariantAnalysisRepoStatus.Failed | VariantAnalysi } }; -export const VariantAnalysisAnalyzedRepoItem = ({ +export type RepoRowProps = { + // Only fullName is required + repository: Partial & Pick; + status?: VariantAnalysisRepoStatus; + resultCount?: number; + + interpretedResults?: AnalysisAlert[]; + rawResults?: AnalysisRawResults; +} + +export const RepoRow = ({ repository, status, resultCount, interpretedResults, rawResults, -}: VariantAnalysisAnalyzedRepoItemProps) => { +}: RepoRowProps) => { const [isExpanded, setExpanded] = useState(false); const toggleExpanded = useCallback(() => { setExpanded(oldIsExpanded => !oldIsExpanded); }, []); - const disabled = !isCompletedAnalysisRepoStatus(status); + const disabled = !status || !isCompletedAnalysisRepoStatus(status); return (
- {isExpanded ? : } + + {isExpanded ? : + } {resultCount === undefined ? '-' : formatDecimal(resultCount)} {repository.fullName} - {repository.private ? 'private' : 'public'} + {status === VariantAnalysisRepoStatus.Succeeded && } - {(status === VariantAnalysisRepoStatus.Failed || status === VariantAnalysisRepoStatus.TimedOut || status === VariantAnalysisRepoStatus.Canceled) && } + {(status === VariantAnalysisRepoStatus.Failed || status === VariantAnalysisRepoStatus.TimedOut || status === VariantAnalysisRepoStatus.Canceled) && + } {status === VariantAnalysisRepoStatus.InProgress && } + {!status && } - {isExpanded && } + {isExpanded && status && + }
); }; diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisAnalyzedRepos.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisAnalyzedRepos.tsx index dff62628b08..153fc4c932c 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisAnalyzedRepos.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisAnalyzedRepos.tsx @@ -1,13 +1,13 @@ import * as React from 'react'; import styled from 'styled-components'; import { VariantAnalysis, VariantAnalysisScannedRepositoryResult } from '../../remote-queries/shared/variant-analysis'; -import { VariantAnalysisAnalyzedRepoItem } from './VariantAnalysisAnalyzedRepoItem'; +import { RepoRow } from './RepoRow'; import { useMemo } from 'react'; const Container = styled.div` display: flex; flex-direction: column; - gap: 1em; + gap: 0.5em; `; export type VariantAnalysisAnalyzedReposProps = { @@ -33,7 +33,7 @@ export const VariantAnalysisAnalyzedRepos = ({ const results = repositoryResultsById.get(repository.repository.id); return ( - {getSkipReasonAlert(alertTitle, alertMessage, skippedRepositoryGroup)} {skippedRepositoryGroup.repositories.map((repo) => - + )} ); diff --git a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisSkippedRepositoryRow.tsx b/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisSkippedRepositoryRow.tsx deleted file mode 100644 index deb8d9d06df..00000000000 --- a/extensions/ql-vscode/src/view/variant-analysis/VariantAnalysisSkippedRepositoryRow.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { VSCodeBadge, VSCodeCheckbox } from '@vscode/webview-ui-toolkit/react'; -import * as React from 'react'; -import styled from 'styled-components'; -import { Codicon, WarningIcon } from '../common'; -import { VariantAnalysisSkippedRepository as SkippedRepo } from '../../remote-queries/shared/variant-analysis'; - -export type VariantAnalysisSkippedRepositoryRowProps = { - repository: SkippedRepo, -}; - -const Row = styled.div` - display: flex; - flex-direction: row; - gap: 0.5em; - align-items: center; -`; - -const ChevronIcon = styled(Codicon)` - color: var(--vscode-disabledForeground); -`; - -const PrivacyText = styled.span` - font-size: small; - color: var(--vscode-descriptionForeground); -`; - -function getPrivacyElement(isPrivate: boolean | undefined) { - if (isPrivate === undefined) { - return undefined; - } - const text = isPrivate ? 'private' : 'public'; - return {text}; -} - -export const VariantAnalysisSkippedRepositoryRow = ({ - repository, -}: VariantAnalysisSkippedRepositoryRowProps) => { - return ( - - - - - - {repository.fullName} - {getPrivacyElement(repository.private)} - - - ); -}; diff --git a/extensions/ql-vscode/src/view/variant-analysis/__tests__/VariantAnalysisAnalyzedRepoItem.spec.tsx b/extensions/ql-vscode/src/view/variant-analysis/__tests__/RepoRow.spec.tsx similarity index 76% rename from extensions/ql-vscode/src/view/variant-analysis/__tests__/VariantAnalysisAnalyzedRepoItem.spec.tsx rename to extensions/ql-vscode/src/view/variant-analysis/__tests__/RepoRow.spec.tsx index 4b96fd144f9..3139a4db0bd 100644 --- a/extensions/ql-vscode/src/view/variant-analysis/__tests__/VariantAnalysisAnalyzedRepoItem.spec.tsx +++ b/extensions/ql-vscode/src/view/variant-analysis/__tests__/RepoRow.spec.tsx @@ -1,16 +1,13 @@ import * as React from 'react'; import { render as reactRender, screen } from '@testing-library/react'; import { VariantAnalysisRepoStatus } from '../../../remote-queries/shared/variant-analysis'; -import { - VariantAnalysisAnalyzedRepoItem, - VariantAnalysisAnalyzedRepoItemProps -} from '../VariantAnalysisAnalyzedRepoItem'; import userEvent from '@testing-library/user-event'; +import { RepoRow, RepoRowProps } from '../RepoRow'; -describe(VariantAnalysisAnalyzedRepoItem.name, () => { - const render = (props: Partial = {}) => { +describe(RepoRow.name, () => { + const render = (props: Partial = {}) => { return reactRender( - { })).toBeEnabled(); }); - it('shows the repo as public', () => { + it('shows repository name', async () => { + render({ + repository: { + fullName: 'octodemo/hello-world', + } + }); + + expect(screen.getByText('octodemo/hello-world')).toBeInTheDocument(); + }); + + it('shows visibility when public', () => { render({ repository: { id: 1, @@ -117,7 +124,7 @@ describe(VariantAnalysisAnalyzedRepoItem.name, () => { expect(screen.getByText('public')).toBeInTheDocument(); }); - it('shows the repo as private', () => { + it('shows visibility when private', () => { render({ repository: { id: 1, @@ -129,6 +136,19 @@ describe(VariantAnalysisAnalyzedRepoItem.name, () => { expect(screen.getByText('private')).toBeInTheDocument(); }); + it('does not show visibility when unknown', () => { + render({ + repository: { + id: undefined, + fullName: 'octodemo/hello-world-1', + private: undefined, + } + }); + + expect(screen.queryByText('public')).not.toBeInTheDocument(); + expect(screen.queryByText('private')).not.toBeInTheDocument(); + }); + it('can expand the repo item', async () => { render({ status: VariantAnalysisRepoStatus.TimedOut, @@ -143,4 +163,14 @@ describe(VariantAnalysisAnalyzedRepoItem.name, () => { }); screen.getByText('Error: Timed out'); }); + + it('does not allow expanding the repo item when status is undefined', async () => { + render({ + status: undefined, + }); + + expect(screen.getByRole('button', { + expanded: false + })).toBeDisabled(); + }); }); diff --git a/extensions/ql-vscode/src/view/variant-analysis/__tests__/VariantAnalysisSkippedRepositoryRow.spec.tsx b/extensions/ql-vscode/src/view/variant-analysis/__tests__/VariantAnalysisSkippedRepositoryRow.spec.tsx deleted file mode 100644 index 4e108fac884..00000000000 --- a/extensions/ql-vscode/src/view/variant-analysis/__tests__/VariantAnalysisSkippedRepositoryRow.spec.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import * as React from 'react'; -import { render as reactRender, screen } from '@testing-library/react'; -import { VariantAnalysisSkippedRepositoryRow, VariantAnalysisSkippedRepositoryRowProps } from '../VariantAnalysisSkippedRepositoryRow'; - -describe(VariantAnalysisSkippedRepositoryRow.name, () => { - const render = (props: VariantAnalysisSkippedRepositoryRowProps) => - reactRender(); - - it('shows repository name', async () => { - render({ - repository: { - fullName: 'octodemo/hello-world', - } - }); - - expect(screen.getByText('octodemo/hello-world')).toBeInTheDocument(); - }); - - it('shows visibility when public', async () => { - render({ - repository: { - fullName: 'octodemo/hello-world', - private: false, - } - }); - - expect(screen.getByText('public')).toBeInTheDocument(); - expect(screen.queryByText('private')).not.toBeInTheDocument(); - }); - - it('shows visibility when private', async () => { - render({ - repository: { - fullName: 'octodemo/hello-world', - private: true, - } - }); - - expect(screen.queryByText('public')).not.toBeInTheDocument(); - expect(screen.getByText('private')).toBeInTheDocument(); - }); - - it('does not show visibility when unknown', async () => { - render({ - repository: { - fullName: 'octodemo/hello-world', - } - }); - - expect(screen.queryByText('public')).not.toBeInTheDocument(); - expect(screen.queryByText('private')).not.toBeInTheDocument(); - }); -});