Skip to content

Commit

Permalink
feat(frontend): add analyzer score summary (#2735)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgeepc committed Jun 16, 2023
1 parent 592188a commit 65a7fa4
Show file tree
Hide file tree
Showing 14 changed files with 109 additions and 21 deletions.
3 changes: 3 additions & 0 deletions api/tests.yaml
Expand Up @@ -73,6 +73,9 @@ components:
fails:
type: integer
readOnly: true
analyzerScore:
type: integer
readOnly: true

TestSpecs:
type: object
Expand Down
40 changes: 37 additions & 3 deletions cli/openapi/model_test_summary_last_run.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions server/http/mappings/tests.go
Expand Up @@ -65,9 +65,10 @@ func (m OpenAPI) Test(in model.Test) openapi.Test {
Summary: openapi.TestSummary{
Runs: int32(in.Summary.Runs),
LastRun: openapi.TestSummaryLastRun{
Time: optionalTime(in.Summary.LastRun.Time),
Passes: int32(in.Summary.LastRun.Passes),
Fails: int32(in.Summary.LastRun.Fails),
Time: optionalTime(in.Summary.LastRun.Time),
Passes: int32(in.Summary.LastRun.Passes),
Fails: int32(in.Summary.LastRun.Fails),
AnalyzerScore: int32(in.Summary.LastRun.AnalyzerScore),
},
},
}
Expand Down
7 changes: 4 additions & 3 deletions server/model/tests.go
Expand Up @@ -40,9 +40,10 @@ type (
}

LastRun struct {
Time time.Time `json:"time"`
Passes int `json:"passes"`
Fails int `json:"fails"`
Time time.Time `json:"time"`
Passes int `json:"passes"`
Fails int `json:"fails"`
AnalyzerScore int `json:"analyzerScore"`
}

TriggerType string
Expand Down
2 changes: 2 additions & 0 deletions server/openapi/model_test_summary_last_run.go
Expand Up @@ -19,6 +19,8 @@ type TestSummaryLastRun struct {
Passes int32 `json:"passes,omitempty"`

Fails int32 `json:"fails,omitempty"`

AnalyzerScore int32 `json:"analyzerScore,omitempty"`
}

// AssertTestSummaryLastRunRequired checks if the required fields are not zero-ed
Expand Down
13 changes: 11 additions & 2 deletions server/testdb/tests.go
Expand Up @@ -163,7 +163,8 @@ const (
(SELECT COUNT(*) FROM test_runs tr WHERE tr.test_id = t.id) as total_runs,
last_test_run.created_at as last_test_run_time,
last_test_run.pass as last_test_run_pass,
last_test_run.fail as last_test_run_fail
last_test_run.fail as last_test_run_fail,
last_test_run.linter as last_test_run_linter
FROM tests t
LEFT OUTER JOIN (
SELECT MAX(id) as id, test_id FROM test_runs GROUP BY test_id
Expand Down Expand Up @@ -316,7 +317,8 @@ func (td *postgresDB) readTestRow(ctx context.Context, row scanner) (model.Test,
var (
jsonServiceUnderTest,
jsonSpecs,
jsonOutputs []byte
jsonOutputs,
jsonLinter []byte

lastRunTime *time.Time

Expand All @@ -335,6 +337,7 @@ func (td *postgresDB) readTestRow(ctx context.Context, row scanner) (model.Test,
&lastRunTime,
&pass,
&fail,
&jsonLinter,
)

switch err {
Expand Down Expand Up @@ -364,6 +367,12 @@ func (td *postgresDB) readTestRow(ctx context.Context, row scanner) (model.Test,
test.Summary.LastRun.Fails = *fail
}

var linter model.LinterResult
err = json.Unmarshal(jsonLinter, &linter)
if err == nil {
test.Summary.LastRun.AnalyzerScore = linter.Score
}

return test, nil
case sql.ErrNoRows:
return model.Test{}, ErrNotFound
Expand Down
9 changes: 6 additions & 3 deletions server/tests/transactions_test.go
Expand Up @@ -303,7 +303,8 @@ func TestTransactions(t *testing.T) {
"lastRun": {
"time": "REMOVEME",
"passes": 2,
"fails": 1
"fails": 1,
"analyzerScore": 0
}
}
},
Expand Down Expand Up @@ -340,7 +341,8 @@ func TestTransactions(t *testing.T) {
"lastRun": {
"fails": 0,
"passes": 0,
"time": "REMOVEME"
"time": "REMOVEME",
"analyzerScore": 0
}
}
}
Expand All @@ -350,7 +352,8 @@ func TestTransactions(t *testing.T) {
"lastRun": {
"fails": 1,
"passes": 2,
"time": "REMOVEME"
"time": "REMOVEME",
"analyzerScore": 0
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/ResourceCard/ResourceCard.styled.ts
Expand Up @@ -130,7 +130,7 @@ export const RunsListContainer = styled.div`
export const TestContainer = styled.div`
cursor: pointer;
display: grid;
grid-template-columns: auto auto 1fr 100px auto auto;
grid-template-columns: auto auto 1fr 28px auto auto auto;
align-items: center;
gap: 18px;
padding: 15px 24px;
Expand Down
14 changes: 12 additions & 2 deletions web/src/components/ResourceCard/ResourceCardSummary.tsx
@@ -1,6 +1,7 @@
import {Tooltip} from 'antd';
import Date from 'utils/Date';
import AnalyzerScore from 'components/AnalyzerScore';
import Summary from 'models/Summary.model';
import Date from 'utils/Date';
import * as S from './ResourceCard.styled';

interface IProps {
Expand All @@ -9,10 +10,19 @@ interface IProps {

const ResourceCardSummary = ({
summary: {
lastRun: {time, passes, fails},
lastRun: {time, passes, fails, analyzerScore},
},
}: IProps) => (
<>
<div>
{!!analyzerScore && (
<Tooltip title="Trace Analyzer score">
<div>
<AnalyzerScore width="28px" height="28px" score={analyzerScore} />
</div>
</Tooltip>
)}
</div>
<div>
<S.Text>Last run result:</S.Text>
<S.Row>
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/ResourceCard/TestCard.tsx
Expand Up @@ -62,7 +62,7 @@ const TestCard = ({onEdit, onDelete, onRun, onViewAll, test}: IProps) => {
shouldEdit={shouldEdit}
onDelete={() => onDelete(test.id, test.name, ResourceType.Test)}
onEdit={() => onEdit(test.id, lastRunId, ResourceType.Test)}
/>
/>
</S.Row>
</S.TestContainer>

Expand Down
3 changes: 2 additions & 1 deletion web/src/components/RunCard/RunCard.styled.ts
Expand Up @@ -71,6 +71,7 @@ export const Title = styled(Typography.Title).attrs({level: 3})`
}
`;

export const Row = styled.div`
export const Row = styled.div<{$minWidth?: number}>`
display: flex;
min-width: ${({$minWidth}) => $minWidth && `${$minWidth}px`};
`;
25 changes: 23 additions & 2 deletions web/src/components/RunCard/TestRunCard.tsx
@@ -1,11 +1,15 @@
import {Tooltip} from 'antd';
import {Link} from 'react-router-dom';
import {Link, useNavigate} from 'react-router-dom';
import AnalyzerScore from 'components/AnalyzerScore';
import RunActionsMenu from 'components/RunActionsMenu';
import TestState from 'components/TestState';
import TestRun, {isRunStateFailed, isRunStateFinished, isRunStateStopped} from 'models/TestRun.model';
import Date from 'utils/Date';
import * as S from './RunCard.styled';

const TEST_RUN_TRACE_TAB = 'trace';
const TEST_RUN_TEST_TAB = 'test';

interface IProps {
run: TestRun;
testId: string;
Expand Down Expand Up @@ -42,11 +46,20 @@ const TestRunCard = ({
testId,
linkTo,
}: IProps) => {
const navigate = useNavigate();
const metadataName = metadata?.name;
const metadataBuildNumber = metadata?.buildNumber;
const metadataBranch = metadata?.branch;
const metadataUrl = metadata?.url;

const handleResultClick = (
event: React.MouseEvent<HTMLDivElement, MouseEvent>,
type: typeof TEST_RUN_TRACE_TAB | typeof TEST_RUN_TEST_TAB
) => {
event.preventDefault();
navigate(`${linkTo}/${type}`);
};

return (
<Link to={linkTo}>
<S.Container $isWhite data-cy={`run-card-${runId}`}>
Expand Down Expand Up @@ -80,8 +93,16 @@ const TestRunCard = ({
</div>
)}

{isRunStateFinished(state) && !!linter.plugins.length && (
<Tooltip title="Trace Analyzer score">
<div onClick={event => handleResultClick(event, TEST_RUN_TRACE_TAB)}>
<AnalyzerScore width="28px" height="28px" score={linter.score} />
</div>
</Tooltip>
)}

{isRunStateFinished(state) && (
<S.Row>
<S.Row $minWidth={70} onClick={event => handleResultClick(event, TEST_RUN_TEST_TAB)}>
<Tooltip title="Passed assertions">
<S.HeaderDetail>
<S.HeaderDot $passed />
Expand Down
2 changes: 2 additions & 0 deletions web/src/models/Summary.model.ts
Expand Up @@ -8,6 +8,7 @@ type Summary = {
time: string;
passes: number;
fails: number;
analyzerScore: number;
};
};

Expand All @@ -18,6 +19,7 @@ const Summary = (summary: TRawTestSummary = {}): Summary => ({
time: summary.lastRun?.time ?? '',
passes: summary.lastRun?.passes ?? 0,
fails: summary.lastRun?.fails ?? 0,
analyzerScore: summary.lastRun?.analyzerScore ?? 0,
},
});

Expand Down
1 change: 1 addition & 0 deletions web/src/types/Generated.types.ts
Expand Up @@ -1814,6 +1814,7 @@ export interface external {
time?: string | null;
passes?: number;
fails?: number;
analyzerScore?: number;
};
};
/** @example [object Object] */
Expand Down

0 comments on commit 65a7fa4

Please sign in to comment.