Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#2109] Add search by tag functionality #2167

Merged
merged 16 commits into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/ug/usingReports.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ The `Tool Bar` at the top of the Chart panel provides a set of configuration opt
* Multiple keywords/terms can be used, separated by spaces.
* Entries that contain _any_ (not necessarily _all_) of the search terms will be displayed.
* The keywords used to filter the author and repository are case-insensitive.
* Starting a search with `tag:` will filter author and repository by git tags. Similar search rules as above (like separating multiple tag names by space) apply.
* `Group by`: grouping criteria for the rows of results.
* `None`: results will not be grouped in any particular way.
* `Repo/Branch`: results will be grouped by repositories and its' associating branches.
Expand Down
119 changes: 115 additions & 4 deletions frontend/cypress/tests/chartView/chartView_toolBar_searchBox.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ describe('search bar', () => {
.type('abcdef')
.type('{enter}');

// Enter does not work. Related issue: https://github.com/cypress-io/cypress/issues/3405
// Let's manually submit form
cy.get('#summary-wrapper form.summary-picker')
.submit();

Expand All @@ -23,8 +21,6 @@ describe('search bar', () => {
.type('Yong Hao TENG')
.type('{enter}');

// Enter does not work. Related issue: https://github.com/cypress-io/cypress/issues/3405
// Let's manually submit form
cy.get('#summary-wrapper form.summary-picker')
.submit();

Expand All @@ -33,4 +29,119 @@ describe('search bar', () => {
expect(children).to.equal(1);
});
});

it('searching by non-existent tag shows no results', () => {
cy.get('#app #tab-resize .tab-close').click();
cy.get('#summary-wrapper input[type=text]')
.type('tag: asdfghjkl')
.type('{enter}');

cy.get('#summary-wrapper form.summary-picker')
.submit();

cy.get('#summary-wrapper #summary-charts')
.should('be.empty');
});

it("searching tag that only exists in one author's commits shows one result", () => {
cy.get('#app #tab-resize .tab-close').click();
cy.get('#summary-wrapper input[type=text]')
.type('tag: v1.8')
.type('{enter}');

cy.get('#summary-wrapper form.summary-picker')
.submit();

cy.get('.summary-chart__title--name')
.should('have.length', 1)
.and('contain', 'Eugene (eugenepeh)');

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

cy.get('.zoom__title--tags > .tag span')
.should('contain', 'v1.8');
});

it("searching tag that only exists in two authors' commits shows two results", () => {
cy.get('#app #tab-resize .tab-close').click();
cy.get('#summary-wrapper input[type=text]')
.type('tag: v1.10')
.type('{enter}');

cy.get('#summary-wrapper form.summary-picker')
.submit();

cy.get('.summary-chart__title--name')
.should('have.length', 2)
.and('contain', 'Eugene (eugenepeh)')
.and('contain', 'James (jamessspanggg)');

cy.get('.icon-button.fa-list-ul')
.should('exist')
.each(($ele) => {
cy.wrap($ele).click();
cy.get('.zoom__title--tags > .tag span')
.should('contain', 'v1.10');
});
});

it("search field doesn't start with 'tag:' prefix but still contains it shows no results", () => {
cy.get('#app #tab-resize .tab-close').click();
cy.get('#summary-wrapper input[type=text]')
.type('v1.10 tag: v1.10')
.type('{enter}');

cy.get('#summary-wrapper form.summary-picker')
.submit();

cy.get('#summary-wrapper #summary-charts')
.should('be.empty');
});

it("search field doesn't contain 'tag:' at all shows no results", () => {
cy.get('#app #tab-resize .tab-close').click();
cy.get('#summary-wrapper input[type=text]')
.type('v1.10')
.type('{enter}');

cy.get('#summary-wrapper form.summary-picker')
.submit();

cy.get('#summary-wrapper #summary-charts')
.should('be.empty');
});

it('searching for multiple tags shows results containing all the tags searched', () => {
cy.get('#app #tab-resize .tab-close').click();
cy.get('#summary-wrapper input[type=text]')
.type('tag: bb v1.10')
.type('{enter}');

cy.get('#summary-wrapper form.summary-picker')
.submit();

cy.get('.summary-chart__title--name')
.should('have.length', 2)
.and('contain', 'Eugene (eugenepeh)')
.and('contain', 'James (jamessspanggg)');

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

cy.get('.zoom__title--tags > .tag span')
.should('contain', 'bb');

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

cy.get('.zoom__title--tags > .tag span')
.should('contain', 'v1.10');
});
});
71 changes: 55 additions & 16 deletions frontend/src/views/c-summary.vue
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,11 @@ import {
CommitResult,
} from '../types/types';
import { ErrorMessage } from '../types/zod/summary-type';
import { AuthorFileTypeContributions, FileTypeAndContribution } from '../types/zod/commits-type';
import {
AuthorDailyContributions,
AuthorFileTypeContributions,
FileTypeAndContribution,
} from '../types/zod/commits-type';
import { ZoomInfo } from '../types/vuex.d';
import {
FilterGroupSelection, FilterTimeFrame, SortGroupSelection, SortWithinGroupSelection,
Expand Down Expand Up @@ -473,6 +477,13 @@ export default defineComponent({
.some((param) => user.searchPath.includes(param));
},

isMatchSearchedTag(filterSearch: string, tag: string) {
return !filterSearch || filterSearch.toLowerCase()
.split(' ')
.filter(Boolean)
.some((param) => tag.includes(param));
},

toggleBreakdown() {
// Reset the file type filter
if (this.checkedFileTypes.length !== this.fileTypes.length) {
Expand All @@ -494,31 +505,59 @@ export default defineComponent({
getFilteredRepos() {
// array of array, sorted by repo
const full: Array<Array<User>> = [];
const tagSearchPrefix = 'tag:';

// create deep clone of this.repos to not modify the original content of this.repos
// when merging groups
const groups = this.hasMergedGroups() ? JSON.parse(JSON.stringify(this.repos)) as Array<Repo> : this.repos;
groups.forEach((repo) => {
const res: Array<User> = [];

// filtering
repo.users?.forEach((user) => {
if (this.isMatchSearchedUser(this.filterSearch, user)) {
this.getUserCommits(user, this.filterSinceDate, this.filterUntilDate);
if (this.filterTimeFrame === 'week') {
this.splitCommitsWeek(user, this.filterSinceDate, this.filterUntilDate);
if (this.filterSearch.startsWith(tagSearchPrefix)) {
const searchedTags = this.filterSearch.split(tagSearchPrefix)[1];
groups.forEach((repo) => {
const commits = repo.commits;
if (!commits) return;

const res: Array<User> = [];
Object.entries(commits.authorDailyContributionsMap).forEach(([author, contributions]) => {
contributions = contributions as Array<AuthorDailyContributions>;
const tags = contributions.flatMap((c) => c.commitResults).flatMap((r) => r.tags);

if (tags.some((tag) => tag && this.isMatchSearchedTag(searchedTags, tag))) {
const user = repo.users?.find((u) => u.name === author);
if (user) {
this.updateCheckedFileTypeContribution(user);
res.push(user);
}
}
this.updateCheckedFileTypeContribution(user);
res.push(user);
});

if (res.length) {
full.push(res);
}
});
} else {
groups.forEach((repo) => {
const res: Array<User> = [];

// filtering
repo.users?.forEach((user) => {
if (this.isMatchSearchedUser(this.filterSearch, user)) {
this.getUserCommits(user, this.filterSinceDate, this.filterUntilDate);
if (this.filterTimeFrame === 'week') {
this.splitCommitsWeek(user, this.filterSinceDate, this.filterUntilDate);
}
this.updateCheckedFileTypeContribution(user);
res.push(user);
}
});

if (res.length) {
full.push(res);
}
});
this.filtered = full;
if (res.length) {
full.push(res);
}
});
}

this.filtered = full;
this.getOptionWithOrder();

const filterControl = {
Expand Down
Loading