Skip to content

Commit

Permalink
Add optimise timeline feature (#2180)
Browse files Browse the repository at this point in the history
Add optimise timeline feature

Currently, the ramps have a lot of empty space if the since and until
dates are specified far apart. 

Let's add a checkbox that can eliminate this empty space for each ramp.
This is especially useful if RepoSense is to be used to set up a report
of an individual's past OSS contributions.
  • Loading branch information
jonasongg authored May 6, 2024
1 parent 29b9f5f commit 2457ebb
Show file tree
Hide file tree
Showing 6 changed files with 293 additions and 30 deletions.
1 change: 1 addition & 0 deletions docs/ug/usingReports.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ The `Tool Bar` at the top of the Chart panel provides a set of configuration opt
* `Merge group`: merges all the ramp charts of each group into a single ramp chart; aggregates the contribution of each group.
* viewing of authored code of the group as a whole is available when `group by repos`.
* `Show tags`: shows the tags of all the repos under a group
* `Trim timeline`: trims the starting and ending portion of each ramp where no commits were made; only the part of each ramp where commits were made will be shown.

Notes:<br>
[1] **`Sort groups by`**: each main group has its own index and percentile according to its ranking position after sorting (e.g., if the groups are sorted by contribution in descending order, a 25% percentile indicates that the group is in the top 25% of the whole cohort in terms of contribution)<br>.
Expand Down
151 changes: 151 additions & 0 deletions frontend/cypress/tests/chartView/chartView_optimiseTimeline.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
describe('optimise timeline', () => {
it('ramp padding should only exist when optimise timeline is checked', () => {
cy.get('#summary label.optimise-timeline > input:visible')
.should('be.visible')
.uncheck()
.should('be.not.checked');

cy.get('#summary-charts .summary-chart')
.first()
.find('.summary-chart__ramp .ramp .ramp-padding')
.should('have.css', 'left', '0px');

cy.get('#summary label.optimise-timeline > input:visible')
.should('be.visible')
.check()
.should('be.checked');

cy.get('#summary-charts .summary-chart')
.first()
.find('.summary-chart__ramp .ramp .ramp-padding')
.should('have.not.css', 'left', '0px');
});

it('should retain the same number of ramp slices', () => {
cy.get('#summary-charts .summary-chart')
.first()
.find('.summary-chart__ramp .ramp .ramp-padding a')
.then(($el) => {
const rampSlices = $el.length;

cy.get('#summary label.optimise-timeline > input:visible')
.should('be.visible')
.check()
.should('be.checked');

cy.get('#summary-charts .summary-chart')
.first()
.find('.summary-chart__ramp .ramp .ramp-padding a')
.should('have.length', rampSlices);
});
});

it('start and end date indicators should exist', () => {
cy.get('#summary label.optimise-timeline > input:visible')
.should('be.visible')
.check()
.should('be.checked');

cy.get('#summary-charts .summary-chart')
.first()
.find('.summary-chart__ramp .date-indicators span')
.first()
.should('have.text', '2018-05-03');

cy.get('#summary-charts .summary-chart')
.first()
.find('.summary-chart__ramp .date-indicators span')
.last()

// 3/3 on GitHub CI, 3/4 on local
.should('have.text', '2023-03-03');
});

it('no commits in range should not have date indicators', () => {
cy.get('#summary label.optimise-timeline > input:visible')
.should('be.visible')
.check()
.should('be.checked');

// change since date
cy.get('input[name="since"]')
.type('2018-12-31');

// change until date
cy.get('input[name="until"]')
.type('2019-01-01');

cy.get('#summary-charts .summary-chart')
.first()
.find('.summary-chart__ramp .date-indicators')
.should('not.exist');
});

it('zoom panel range should work correctly when timeline is optimised', () => {
cy.get('.icon-button.fa-list-ul')
.should('exist')
.first()
.click();

cy.get('#tab-zoom')
.should('be.visible');

// verifies the ramp chart is not optimised and has empty space on the right
cy.get('#tab-zoom .ramp a')
.first()
.invoke('css', 'right')
.then((val) => parseFloat(val))
.should('gt', 0);

cy.get('#summary label.optimise-timeline > input')
.check()
.should('be.checked');

cy.get('.icon-button.fa-list-ul')
.should('exist')
.first()
.click();

cy.get('#tab-zoom')
.should('be.visible');

// verifies the date range is correctly optimised
cy.get('#tab-zoom .period')
.should('contain', '2018-05-03 to 2023-03-03');

// verifies the ramp chart is optimised and has no empty space on the right
cy.get('#tab-zoom .ramp a')
.first()
.invoke('css', 'right')
.then((val) => parseFloat(val))
.should('lt', 1);
});

it('subzoom panel range should work correctly when timeline is optimised', () => {
const zoomKey = Cypress.platform === 'darwin' ? '{meta}' : '{ctrl}';

cy.get('#summary label.optimise-timeline > input:visible')
.should('be.visible')
.check()
.should('be.checked');

// clicking from the 10th px to the 50th px in the ramp
cy.get('body').type(zoomKey, { release: false })
.get('#summary-charts .summary-chart__ramp .ramp')
.first()
.click(110, 20)
.click(120, 20);

cy.get('#tab-zoom')
.should('be.visible');

cy.get('#tab-zoom .ramp .ramp__slice')
.should('have.length', 1);

cy.get('#tab-zoom .ramp .ramp__slice')
.invoke('attr', 'title')
.then((title) => {
cy.wrap(title).should('eq', '[2019-08-18] AboutUs: update team members (#867): +94 -12 lines ');
});
});
});
14 changes: 14 additions & 0 deletions frontend/cypress/tests/codeView/codeView_renderFilterHash.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,20 @@ describe('render filter hash', () => {
.should('contain', 'viewRepoTags=true');
});

it('optimise timeline: url params should persist after change and reload', () => {
cy.get('#summary label.optimise-timeline input:visible')
.should('be.visible')
.check();

cy.url()
.should('contain', 'optimiseTimeline=true');

cy.reload();

cy.url()
.should('contain', 'optimiseTimeline=true');
});

it('checked file types: url params should persist after change and reload', () => {
cy.get('#summary label.filter-breakdown input:visible')
.should('not.be.checked');
Expand Down
83 changes: 62 additions & 21 deletions frontend/src/components/c-ramp.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
<template lang="pug">
.ramp
template(v-if="tframe === 'commit'")
template(v-for="(slice, j) in user.commits")
template(v-for="(commit, k) in slice.commitResults")
a.ramp__slice(
draggable="false",
v-on:click="rampClick",
v-bind:href="getLink(commit)", target="_blank",
v-bind:title="getContributionMessageByCommit(slice, commit)",
v-bind:class="`ramp__slice--color${getRampColor(commit, slice)}`,\
!isBrokenLink(getLink(commit)) ? '' : 'broken-link'",
v-bind:style="{\
zIndex: user.commits.length - j,\
borderLeftWidth: `${getWidth(commit)}em`,\
right: `${((getSlicePos(slice.date)\
+ (getCommitPos(k, slice.commitResults.length))) * 100)}%`\
}"
)
.ramp-padding(
v-bind:style="optimiseTimeline ? {width: `${100 - optimisedPadding * 2}%`, left: `${optimisedPadding}%`} : ''"
)
template(v-for="(slice, j) in user.commits")
template(v-for="(commit, k) in slice.commitResults")
a.ramp__slice(
draggable="false",
v-on:click="rampClick",
v-bind:href="getLink(commit)", target="_blank",
v-bind:title="getContributionMessageByCommit(slice, commit)",
v-bind:class="`ramp__slice--color${getRampColor(commit, slice)}`,\
!isBrokenLink(getLink(commit)) ? '' : 'broken-link'",
v-bind:style="{\
zIndex: user.commits.length - j,\
borderLeftWidth: `${getWidth(commit)}em`,\
right: `${((getSlicePos(slice.date)\
+ (getCommitPos(k, slice.commitResults.length))) * 100)}%`\
}"
)

template(v-else)
a(v-bind:href="getReportLink()", target="_blank")
Expand All @@ -30,8 +33,11 @@
zIndex: user.commits.length - j,\
borderLeftWidth: `${getWidth(slice)}em`,\
right: `${(getSlicePos(tframe === 'day' ? slice.date : slice.endDate) * 100)}%` \
}"
}"
)
.date-indicators(v-if="optimiseTimeline")
span {{optimisedMinimumDate}}
span {{optimisedMaximumDate}}
</template>

<script lang='ts'>
Expand Down Expand Up @@ -83,10 +89,26 @@ export default defineComponent({
type: Boolean,
default: false,
},
optimiseTimeline: {
type: Boolean,
default: false,
},
optimisedMinimumDate: {
type: String,
default: '',
},
optimisedMaximumDate: {
type: String,
default: '',
},
},
data(): {rampSize: number} {
data(): {
rampSize: number,
optimisedPadding: number,
} {
return {
rampSize: 0.01 as number,
optimisedPadding: 3, // as % of total timeline,
};
},
Expand Down Expand Up @@ -172,13 +194,20 @@ export default defineComponent({
// position for commit granularity
getCommitPos(i: number, total: number): number {
const totalTime = this.optimiseTimeline
? this.getTotalForPos(this.optimisedMinimumDate, this.optimisedMaximumDate)
: this.getTotalForPos(this.sdate, this.udate);
return (((total - i - 1) * window.DAY_IN_MS) / total)
/ (this.getTotalForPos(this.sdate, this.udate) + window.DAY_IN_MS);
/ (totalTime + window.DAY_IN_MS);
},
// position for day granularity
getSlicePos(date: string): number {
const total = this.getTotalForPos(this.sdate, this.udate);
return (new Date(this.udate).valueOf() - new Date(date).valueOf()) / (total + window.DAY_IN_MS);
const toDate = this.optimiseTimeline ? this.optimisedMaximumDate : this.udate;
const total = this.optimiseTimeline
? this.getTotalForPos(this.optimisedMinimumDate, this.optimisedMaximumDate)
: this.getTotalForPos(this.sdate, this.udate);
return (new Date(toDate).valueOf() - new Date(date).valueOf()) / (total + window.DAY_IN_MS);
},
// get duration in miliseconds between 2 date
Expand Down Expand Up @@ -267,4 +296,16 @@ export default defineComponent({
}
}
}

.ramp-padding {
height: 100%;
position: relative;
}

.date-indicators {
color: mui-color('grey', '700');
display: flex;
justify-content: space-between;
padding-top: 1px;
}
</style>
Loading

0 comments on commit 2457ebb

Please sign in to comment.