Skip to content

Commit

Permalink
Merge branch 'main' into dialog-valadation-required-fields
Browse files Browse the repository at this point in the history
  • Loading branch information
kuthedk committed Jul 4, 2023
2 parents 6584460 + f39c775 commit aaf5fd5
Show file tree
Hide file tree
Showing 13 changed files with 246 additions and 42 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-and-publish-docker-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ env:

jobs:
build-and-push-image:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@v3
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/common-static-analysis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
name: Markdown, Docker, and Shell Static Analysis

on: [push, pull_request, workflow_dispatch]

env:
Expand All @@ -10,7 +9,8 @@ env:

jobs:
docker-shell-markdown-static-analysis:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/draft-paper.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:

jobs:
paper:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
name: JOSS pandoc paper draft
steps:
- name: Checkout
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ defaults:
jobs:
nodejs-ci:

runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name

strategy:
matrix:
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ env:
jobs:
python-ci:

runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name

strategy:
fail-fast: false
matrix:
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/system-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ on: [push, pull_request, workflow_dispatch]

jobs:
system-tests:
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name != github.event.pull_request.base.repo.full_name

steps:
- uses: actions/checkout@v3
Expand Down
13 changes: 9 additions & 4 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,21 +187,26 @@ docker run -v <absolute_path_to_backend>/:/app/ -p 127.0.0.1:8000:8000 <image_id
The backend service uses `pytest` as a testing framework for the Python code. The tests are broken out into unit,
integration, and system tests.

Note: The `-s` flag for the pytest routes the standard out to the console. It allows the `print()` statement to log
Pytest notes:

- In order for Rosalution to work, it requires a ROSALUTION_KEY environment variable to be set. Since the tests are not
actually running Rosalution, this needs to be manually done each time when running pytest.

- The `-s` flag for the pytest routes the standard out to the console. It allows the `print()` statement to log
output of variables for development purposes.

From the root `./` directory of the project:

Unit Tests:

```bash
pytest -s tests/unit
ROSALUTION_KEY="fake-rosalution-key-used-in-pytest" pytest -s tests/unit
```

Integration Tests:

```bash
pytest -s tests/integration
ROSALUTION_KEY="fake-rosalution-key-used-in-pytest" pytest -s tests/integration
```

### Code Coverage
Expand All @@ -218,5 +223,5 @@ Read <https://pytest-cov.readthedocs.io/en/latest/config.html> to learn more abo
tool configuration.

```bash
pytest --cov=src --cov-fail-under=80 --cov-branch --cov-report=term tests/unit/
ROSALUTION_KEY="fake-rosalution-key-used-in-pytest" pytest --cov=src --cov-fail-under=80 --cov-branch --cov-report=term tests/unit/
```
10 changes: 9 additions & 1 deletion backend/tests/unit/core/test_annotation_task.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Tests Annotation Tasks and the creation of them"""
from unittest.mock import patch
import pytest

from src.core.annotation_task import AnnotationTaskFactory, ForgeAnnotationTask, HttpAnnotationTask
Expand Down Expand Up @@ -88,7 +89,14 @@ def test_annotation_extraction_for_genomic_unit(http_annotation_task_gene, hpo_a
} in actual_extractions


def test_annotation_extraction_value_error_exception(http_annotation_task_gene, hpo_annotation_response):
# Patching the temporary helper method that is writing to a file, this will be
# removed once that helper method is no longer needed for the development


@patch("src.core.annotation_task.log_to_file")
def test_annotation_extraction_value_error_exception(
log_to_file_mock, http_annotation_task_gene, hpo_annotation_response
): # pylint: disable=unused-argument
"""Verifying annotation failure does not cause crash in application during extraction"""

# Removing the expected value in the json to force a jq parse error to more closely
Expand Down
90 changes: 67 additions & 23 deletions frontend/src/components/AnalysisListing/AnalysisListingLegend.vue
Original file line number Diff line number Diff line change
@@ -1,44 +1,88 @@
<template>
<div class="legend">
<font-awesome-icon icon="asterisk" size="lg" style="color: var(--rosalution-status-annotation);"/>
<p>Annotating</p>
<font-awesome-icon icon="clipboard-check" size="lg" style="color: var(--rosalution-status-ready);"/>
<p>Ready</p>
<font-awesome-icon icon="book-open" size="lg" style="color: var(--rosalution-status-active)"/>
<p>Active</p>
<font-awesome-icon icon="pause" size="lg" style="color: var(--rosalution-status-on-hold)"/>
<p>On Hold</p>
<font-awesome-icon icon="check" size="lg" style="color: var(--rosalution-status-approved)"/>
<p>Approved</p>
<font-awesome-icon icon="x" size="lg" style="color: var(--rosalution-status-declined)"/>
<p>Declined</p>
<div v-for="status in statuses" :key="status.name" class="status" @click="toggleFilter(status.name)">
<font-awesome-icon :icon="status.icon" size="lg" :style="{
color: isFiltered(status.name)
? `var(--rosalution-status-${status.name})`
: 'var(--rosalution-grey-300)',
}" />
<p :style="{
color: isFiltered(status.name)
? ''
: 'var(--rosalution-grey-300)',
}">
{{ status.displayName }}
</p>
</div>
</div>
</template>

<style scoped>
<script>
import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';
export default {
name: 'analysis-listing-legend',
emits: ['filtered-changed'],
components: {
'font-awesome-icon': FontAwesomeIcon,
},
data() {
return {
activeFilters: [],
statuses: [
{name: 'annotation', displayName: 'Annotating', icon: 'asterisk'},
{name: 'ready', displayName: 'Ready', icon: 'clipboard-check'},
{name: 'active', displayName: 'Active', icon: 'book-open'},
{name: 'on-hold', displayName: 'On Hold', icon: 'pause'},
{name: 'approved', displayName: 'Approved', icon: 'check'},
{name: 'declined', displayName: 'Declined', icon: 'times'},
],
};
},
methods: {
toggleFilter(status) {
const index = this.activeFilters.indexOf(status);
if (index !== -1) {
this.activeFilters.splice(index, 1);
} else {
this.activeFilters.push(status);
}
if (this.activeFilters.length === this.statuses.length) {
this.activeFilters = [];
}
this.$emit('filtered-changed', this.activeFilters);
},
isFiltered(status) {
return this.activeFilters.includes(status) || this.activeFilters.length === 0;
},
},
};
</script>

<style scoped>
.legend {
display: flex;
flex-grow: 0;
flex-direction: row;
justify-content: center;
align-items: center;
gap: 10px;
gap: var(--p-10);
border-radius: var(--content-border-radius);
padding: var(--p-8);
background-color: var(--secondary-background-color);
}
.status {
display: flex;
align-items: center;
user-select: none;
}
.legend p {
line-height: .245rem;
padding-right: var(--p-10);
padding-left: var(--p-10);
}
</style>


<script>
export default {
name: 'analysis-listing-legend',
};
</script>
22 changes: 16 additions & 6 deletions frontend/src/views/AnalysisListingView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<app-footer>
<InputDialog data-test="phenotips-import-dialog"/>
<NotificationDialog data-test="notification-dialog" />
<AnalysisListingLegend/>
<AnalysisListingLegend @filtered-changed="filteredUpdated"/>
</app-footer>
</div>
</template>
Expand Down Expand Up @@ -62,34 +62,44 @@ export default {
store: authStore,
searchText: '',
analysisList: [],
filteredChanged: [],
};
},
computed: {
username() {
return this.store.state.username;
},
filteredAnalysisListing() {
return this.analysisList.filter((analysis) => {
return this.filteredChanged.length === 0 ||
this.filteredChanged.includes(analysis.latest_status.toLowerCase());
});
},
searchedAnalysisListing() {
const lowerCaseSearchText = this.searchText.toLowerCase();
return this.searchText === '' ? this.analysisList : this.analysisList.filter( (analysis) => {
return this.searchText === '' ? this.filteredAnalysisListing : this.filteredAnalysisListing.filter((analysis) => {
return [analysis.name,
analysis.created_date,
analysis.last_modified_date,
analysis.nominated_by,
].some((content) => content.toLowerCase().includes(lowerCaseSearchText)) ||
analysis.genomic_units.some((unit) => {
return (unit.gene && unit.gene.toLowerCase().includes(lowerCaseSearchText)) ||
(unit.transcripts &&
unit.transcripts.some((transcript) => transcript.toLowerCase().includes(lowerCaseSearchText))) ||
(unit.variants && unit.variants.some((variant) => variant.toLowerCase().includes(lowerCaseSearchText)));
(unit.transcripts &&
unit.transcripts.some((transcript) => transcript.toLowerCase().includes(lowerCaseSearchText))) ||
(unit.variants && unit.variants.some((variant) => variant.toLowerCase().includes(lowerCaseSearchText)));
});
} );
});
},
},
created() {
this.getListing();
},
methods: {
filteredUpdated(filteredChanged) {
this.filteredChanged = filteredChanged;
},
async getListing() {
this.analysisList.length = 0;
const analyses = await Analyses.all();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,23 @@ import AnalysisListingLegend from '@/components/AnalysisListing/AnalysisListingL

import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome';

const statuses = [
{name: 'annotation', displayName: 'Annotating', icon: 'asterisk'},
{name: 'ready', displayName: 'Ready', icon: 'clipboard-check'},
{name: 'active', displayName: 'Active', icon: 'book-open'},
{name: 'on-hold', displayName: 'On Hold', icon: 'pause'},
{name: 'approved', displayName: 'Approved', icon: 'check'},
{name: 'declined', displayName: 'Declined', icon: 'times'},
];

/**
* helper function that shadllow mounts and returns the rendered component
* helper function that shallow mounts and returns the rendered component
* @param {props} props props for testing to overwrite default props
* @return {VueWrapper} returns a shallow mounted using props
*/
function getMountedComponent(props) {
const defaultProps = {
statuses,
};

return shallowMount(AnalysisListingLegend, {
Expand All @@ -30,4 +40,55 @@ describe('AnalysisListingLegend.vue', () => {
expect(wrapper.html()).to.contains('Ready');
expect(wrapper.html()).to.contains('Active');
});

it('should all be colored when no statuses are being filtered for', () => {
const wrapper = getMountedComponent();
statuses.forEach((status) => {
expect(wrapper.html()).to.contains(`color: var(--rosalution-status-${status.name})`);
});
});

it('should only color the filtered status', async () => {
const wrapper = getMountedComponent();
const statusElements = wrapper.findAll('.status');
let readyStatus;

for (let i = 0; i < statusElements.length; i++) {
if (statusElements[i].text() === 'Ready') {
readyStatus = statusElements[i];
}
}

if (readyStatus) {
await readyStatus.trigger('click');
expect(wrapper.html()).to.contains('color: var(--rosalution-status-ready)');
statuses.forEach((status) => {
if (status.name !== 'ready') {
expect(wrapper.html()).to.contains(`color: var(--rosalution-grey-300)`);
}
});
} else {
throw new Error('Ready status not found');
}
});

it('should emit a filtered-changed event when a status is clicked', async () => {
const wrapper = getMountedComponent();
const statusElements = wrapper.findAll('.status');
let readyStatus;

for (let i = 0; i < statusElements.length; i++) {
if (statusElements[i].text() === 'Ready') {
readyStatus = statusElements[i];
}
}

if (readyStatus) {
await readyStatus.trigger('click');
expect(wrapper.emitted()).to.have.property('filtered-changed');
expect(wrapper.emitted()['filtered-changed'][0][0]).to.contains('ready');
} else {
throw new Error('Ready status not found');
}
});
});
9 changes: 9 additions & 0 deletions frontend/test/views/AnalysisListingView.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Analyses from '@/models/analyses.js';
import AnalysisCard from '@/components/AnalysisListing/AnalysisCard.vue';
import AnalysisCreateCard from '@/components/AnalysisListing/AnalysisCreateCard.vue';
import AnalysisListingHeader from '@/components/AnalysisListing/AnalysisListingHeader.vue';
import AnalysisListingLegend from '@/components/AnalysisListing/AnalysisListingLegend.vue';
import AnalysisListingView from '@/views/AnalysisListingView.vue';

import NotificationDialog from '@/components/Dialogs/NotificationDialog.vue';
Expand Down Expand Up @@ -135,6 +136,14 @@ describe('AnalysisListingView', () => {

expect(wrapper.vm.$router.push.called).to.be.true;
});

it('should update the filter when the analysis listing header emits the update event', async () => {
const legend = wrapper.findComponent(AnalysisListingLegend);
legend.vm.$emit('filtered-changed', ['Approved']);
await legend.vm.$nextTick();

expect(wrapper.vm.filteredChanged).to.contain('Approved');
});
});

/**
Expand Down
Loading

0 comments on commit aaf5fd5

Please sign in to comment.