Skip to content

Commit

Permalink
Update Timeline for All Versions table on Test Plan Versions Page (#…
Browse files Browse the repository at this point in the history
…773)

* Show all versions in 'Timeline for All Versions' table

* Update timestamp migrations to use more real world change phase change times (avoid exact time being set for when one phase ends and another begins)

* Update import script to have a 'delayed' time on the report being deprecated

* Add td -> th for first column cell for Version Summary and Timeline related tables

* Match sort order described in #719

* Correct deprecation date (#780)

* Compare most recent test plan version to deprecate against

* Correct deprecation date without using the more recent test plan version since it's being set already

---------

Co-authored-by: Erika Miguel <[email protected]>
  • Loading branch information
howard-e and evmiguel authored Sep 21, 2023
1 parent 04c15f6 commit 87abb14
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 31 deletions.
85 changes: 77 additions & 8 deletions client/components/TestPlanVersionsPage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,69 @@ const TestPlanVersionsPage = () => {
return new Date(b.updatedAt) - new Date(a.updatedAt);
});

const timelineForAllVersions = [];

testPlanVersions.forEach(testPlanVersion => {
const event = {
id: testPlanVersion.id,
updatedAt: testPlanVersion.updatedAt
};
timelineForAllVersions.push({ ...event, phase: 'RD' });

if (testPlanVersion.draftPhaseReachedAt)
timelineForAllVersions.push({
...event,
phase: 'DRAFT',
draftPhaseReachedAt: testPlanVersion.draftPhaseReachedAt
});
if (testPlanVersion.candidatePhaseReachedAt)
timelineForAllVersions.push({
...event,
phase: 'CANDIDATE',
candidatePhaseReachedAt: testPlanVersion.candidatePhaseReachedAt
});
if (testPlanVersion.recommendedPhaseReachedAt)
timelineForAllVersions.push({
...event,
phase: 'RECOMMENDED',
recommendedPhaseReachedAt:
testPlanVersion.recommendedPhaseReachedAt
});
if (testPlanVersion.deprecatedAt)
timelineForAllVersions.push({
...event,
phase: 'DEPRECATED',
deprecatedAt: testPlanVersion.deprecatedAt
});
});

const phaseOrder = {
RD: 0,
DRAFT: 1,
CANDIDATE: 2,
RECOMMENDED: 3,
DEPRECATED: 4
};

timelineForAllVersions.sort((a, b) => {
const dateA =
a.recommendedPhaseReachedAt ||
a.candidatePhaseReachedAt ||
a.draftPhaseReachedAt ||
a.deprecatedAt ||
a.updatedAt;
const dateB =
b.recommendedPhaseReachedAt ||
b.candidatePhaseReachedAt ||
b.draftPhaseReachedAt ||
b.deprecatedAt ||
b.updatedAt;

// If dates are the same, compare phases
if (dateA === dateB) return phaseOrder[a.phase] - phaseOrder[b.phase];
return new Date(dateA) - new Date(dateB);
});

const issues = uniqueBy(
testPlanVersions.flatMap(testPlanVersion =>
testPlanVersion.testPlanReports.flatMap(testPlanReport =>
Expand All @@ -198,7 +261,11 @@ const TestPlanVersionsPage = () => {
)
),
item => item.link
);
).sort((a, b) => {
const aCreatedAt = new Date(a.createdAt);
const bCreatedAt = new Date(b.createdAt);
return bCreatedAt - aCreatedAt;
});

return (
<Container id="main" as="main" tabIndex="-1">
Expand Down Expand Up @@ -240,15 +307,15 @@ const TestPlanVersionsPage = () => {
<tbody>
{testPlanVersions.map(testPlanVersion => (
<tr key={testPlanVersion.id}>
<td>
<th>
<VersionString
date={testPlanVersion.updatedAt}
iconColor={getIconColor(
testPlanVersion
)}
autoWidth={false}
/>
</td>
</th>
<td>
{(() => {
// Gets the derived phase even if deprecated by checking
Expand Down Expand Up @@ -376,7 +443,7 @@ const TestPlanVersionsPage = () => {
</tr>
</thead>
<tbody>
{testPlanVersions.map(testPlanVersion => {
{timelineForAllVersions.map(testPlanVersion => {
const versionString = (
<VersionString
date={testPlanVersion.updatedAt}
Expand All @@ -389,8 +456,10 @@ const TestPlanVersionsPage = () => {
const eventBody = getEventBody(testPlanVersion.phase);

return (
<tr key={testPlanVersion.id}>
<td>{getEventDate(testPlanVersion)}</td>
<tr
key={`${testPlanVersion.id}-${testPlanVersion.phase}`}
>
<th>{getEventDate(testPlanVersion)}</th>
<td>
{versionString}&nbsp;{eventBody}
</td>
Expand Down Expand Up @@ -541,12 +610,12 @@ const TestPlanVersionsPage = () => {

return events.map(([phase, date]) => (
<tr key={phase}>
<td>
<th>
{convertDateToString(
date,
'MMM D, YYYY'
)}
</td>
</th>
<td>{getEventBody(phase)}</td>
</tr>
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,21 @@ module.exports = {
for (const testPlanVersion of testPlanVersions) {
const { id, updatedAt, hasTestPlanReport } = testPlanVersion;

if (hasTestPlanReport)
if (hasTestPlanReport) {
const draftPhaseReachedAt = new Date(updatedAt);
draftPhaseReachedAt.setSeconds(
// Set draftPhaseReachedAt to happen 60 seconds after updatedAt for general
// 'correctness' and to help with any app sorts
draftPhaseReachedAt.getSeconds() + 60
);
await queryInterface.sequelize.query(
`UPDATE "TestPlanVersion" SET "draftPhaseReachedAt" = ? WHERE id = ?`,
{
replacements: [updatedAt, id],
replacements: [draftPhaseReachedAt, id],
transaction
}
);
else
} else
await queryInterface.sequelize.query(
`UPDATE "TestPlanVersion" SET phase = ? WHERE id = ?`,
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
// 1178 (Radio Group Example Using aria-activedescendant) TestPlanVersions
const testPlanVersionsToSetToCandidate =
await queryInterface.sequelize.query(
`select "TestPlanVersion".id, phase, "markedFinalAt"
`select "TestPlanVersion".id, phase, "draftPhaseReachedAt", "markedFinalAt"
from "TestPlanVersion"
join "TestPlanReport" on "TestPlanVersion".id = "TestPlanReport"."testPlanVersionId"
where "markedFinalAt" is not null
Expand All @@ -23,15 +23,23 @@ module.exports = {
}
);

const candidatePhaseReachedAt = new Date();
const recommendedPhaseTargetDate = new Date(
candidatePhaseReachedAt
);
recommendedPhaseTargetDate.setDate(
candidatePhaseReachedAt.getDate() + 180
);

for (const testPlanVersion of testPlanVersionsToSetToCandidate) {
const candidatePhaseReachedAt = new Date(
testPlanVersion.draftPhaseReachedAt
);

// Set candidatePhaseReachedAt to draftPhaseReachedAt date (+1 day)
candidatePhaseReachedAt.setDate(
candidatePhaseReachedAt.getDate() + 1
);

const recommendedPhaseTargetDate = new Date(
candidatePhaseReachedAt
);
recommendedPhaseTargetDate.setDate(
candidatePhaseReachedAt.getDate() + 180
);

await queryInterface.sequelize.query(
`update "TestPlanVersion"
set "candidatePhaseReachedAt" = ?,
Expand Down Expand Up @@ -97,7 +105,7 @@ module.exports = {
testPlanVersion.candidatePhaseReachedAt
);

// Update candidatePhaseReachedAt to be the draftPhaseReachedAt date (+1)
// Update candidatePhaseReachedAt to be the draftPhaseReachedAt date (+1 day)
// (because that phase happening before shouldn't be possible)
if (candidatePhaseReachedAt < draftPhaseReachedAt) {
const newCandidatePhaseReachedAt = new Date(
Expand Down Expand Up @@ -126,21 +134,17 @@ module.exports = {
}

if (testPlanVersion.deprecatedAt) {
const deprecatedAt = new Date(testPlanVersion.deprecatedAt);
deprecatedAt.setSeconds(deprecatedAt.getSeconds() - 1);

// Add deprecatedAt for applicable testPlanVersions
await queryInterface.sequelize.query(
`update "TestPlanVersion"
set "deprecatedAt" = ?,
phase = 'DEPRECATED'
where id = ?`,
{
replacements: [
testPlanVersion.recommendedPhaseReachedAt
? testPlanVersion.recommendedPhaseReachedAt
: testPlanVersion.candidatePhaseReachedAt
? testPlanVersion.candidatePhaseReachedAt
: testPlanVersion.deprecatedAt,
testPlanVersion.id
],
replacements: [deprecatedAt, testPlanVersion.id],
transaction
}
);
Expand Down
12 changes: 10 additions & 2 deletions server/scripts/import-tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,19 @@ const importTestPlanVersions = async () => {
});
if (testPlanVersionsToDeprecate.length) {
for (const testPlanVersionToDeprecate of testPlanVersionsToDeprecate) {
if (new Date(testPlanVersionToDeprecate.updatedAt) < updatedAt)
if (
new Date(testPlanVersionToDeprecate.updatedAt) < updatedAt
) {
// Set the deprecatedAt time to a couple seconds less than the updatedAt date.
// Deprecations happen slightly before update during normal app operations.
// This is to maintain correctness and any app sorts issues
const deprecatedAt = new Date(updatedAt);
deprecatedAt.setSeconds(deprecatedAt.getSeconds() - 60);
await updateTestPlanVersion(testPlanVersionToDeprecate.id, {
phase: 'DEPRECATED',
deprecatedAt: updatedAt
deprecatedAt
});
}
}
}

Expand Down

0 comments on commit 87abb14

Please sign in to comment.