Skip to content

Commit

Permalink
[ENG-5024] Feature/dashboard b and i (#2429)
Browse files Browse the repository at this point in the history
-   Ticket: [ENG-5024]
-   Feature flag: `share_download` for downloading projects, registrations, and preprint data

## Purpose
- Add download functionality to Institutional Dashboard
- Add date of report to Summary and Users tab of Institutional Dashboard
- Update language and styling
  • Loading branch information
futa-ikeda authored Dec 11, 2024
1 parent 951bcb2 commit a0fe50f
Show file tree
Hide file tree
Showing 29 changed files with 267 additions and 63 deletions.
1 change: 1 addition & 0 deletions app/config/environment.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ declare const config: {
registrationFilesPage: string;
verifyEmailModals: string;
egapAdmins: string;
shareDownload: string;
};
gReCaptcha: {
siteKey: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ module('Integration | institutions | dashboard | -components | kpi-chart-wrapper
.doesNotExist();
});

test('it calculates the Public vs Private Registration data correctly', async function(assert) {
test('it calculates the Public vs Embargoed Registration data correctly', async function(assert) {
// Given the component is rendered
await render(hbs`
<Institutions::Dashboard::-Components::ChartKpiWrapper
Expand All @@ -127,7 +127,7 @@ module('Integration | institutions | dashboard | -components | kpi-chart-wrapper

// And the title is verified
assert.dom(`${parentDom} [data-test-chart-title]`)
.hasText('Public vs Private Registrations');
.hasText('Public vs Embargoed Registrations');

// And the expanded data position 0 name is verified
assert.dom(`${parentDom} [data-test-expanded-name="0"]`)
Expand All @@ -139,7 +139,7 @@ module('Integration | institutions | dashboard | -components | kpi-chart-wrapper

// And the expanded data position 1 name is verified
assert.dom(`${parentDom} [data-test-expanded-name="1"]`)
.hasText('Private Registrations');
.hasText('Embargoed Registrations');

// And the expanded data position 1 total is verified
assert.dom(`${parentDom} [data-test-expanded-total="1"]`)
Expand Down Expand Up @@ -200,7 +200,7 @@ module('Integration | institutions | dashboard | -components | kpi-chart-wrapper

// And the expanded data position 4 name is verified
assert.dom(`${parentDom} [data-test-expanded-name="4"]`)
.hasText('Private Registrations');
.hasText('Embargoed Registrations');

// And the expanded data position 4 total is verified
assert.dom(`${parentDom} [data-test-expanded-total="4"]`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default class ChartKpiWrapperComponent extends Component<TotalCountChartW
chartType: 'doughnut',
},
{
title: this.intl.t('institutions.dashboard.kpi-chart.public-vs-private-registrations.title'),
title: this.intl.t('institutions.dashboard.kpi-chart.public-vs-embargoed-registrations.title'),
chartData: this.calculateRegistrations(metrics.summaryMetrics),
chartType: 'doughnut',
},
Expand Down Expand Up @@ -133,11 +133,11 @@ export default class ChartKpiWrapperComponent extends Component<TotalCountChartW
private calculateRegistrations(summaryMetrics: InstitutionSummaryMetricModel): ChartDataModel[] {
return [
{
label: this.intl.t('institutions.dashboard.kpi-chart.public-vs-private-registrations.public'),
label: this.intl.t('institutions.dashboard.kpi-chart.public-vs-embargoed-registrations.public'),
total: summaryMetrics.publicRegistrationCount,
} as ChartDataModel,
{
label: this.intl.t('institutions.dashboard.kpi-chart.public-vs-private-registrations.private'),
label: this.intl.t('institutions.dashboard.kpi-chart.public-vs-embargoed-registrations.embargoed'),
total: summaryMetrics.embargoedRegistrationCount,
} as ChartDataModel,
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Intl from 'ember-intl/services/intl';
import InstitutionModel from 'ember-osf-web/models/institution';
import InstitutionDepartmentsModel from 'ember-osf-web/models/institution-department';
import Analytics from 'ember-osf-web/services/analytics';
import { RelationshipWithLinks } from 'osf-api';

interface Column {
key: string;
Expand Down Expand Up @@ -90,7 +91,7 @@ export default class InstitutionalUsersList extends Component<InstitutionalUsers
{
key: 'embargoedRegistrationCount',
sort_key: 'embargoed_registration_count',
label: this.intl.t('institutions.dashboard.users_list.private_registration_count'),
label: this.intl.t('institutions.dashboard.users_list.embargoed_registration_count'),
selected: true,
type: 'string',
},
Expand Down Expand Up @@ -184,6 +185,30 @@ export default class InstitutionalUsersList extends Component<InstitutionalUsers
return query;
}

downloadUrl(format: string) {
const institutionRelationships = this.args.institution.links.relationships;
const usersLink = (institutionRelationships!.user_metrics as RelationshipWithLinks).links.related.href;
const userURL = new URL(usersLink!);
userURL.searchParams.set('format', format);
userURL.searchParams.set('page[size]', '10000');
Object.entries(this.queryUsers).forEach(([key, value]) => {
userURL.searchParams.set(key, value);
});
return userURL.toString();
}

get downloadCsvUrl() {
return this.downloadUrl('csv');
}

get downloadTsvUrl() {
return this.downloadUrl('tsv');
}

get downloadJsonUrl() {
return this.downloadUrl('json_report');
}

@restartableTask
@waitFor
async searchDepartment(name: string) {
Expand Down Expand Up @@ -237,5 +262,4 @@ export default class InstitutionalUsersList extends Component<InstitutionalUsers
clickToggleOrcidFilter(hasOrcid: boolean) {
this.hasOrcid = !hasOrcid;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@
color: $color-select;
}

.download-dropdown-content {
display: flex;
flex-direction: column;
align-items: flex-start;
border: 1px solid $color-border-gray;
width: max-content;
}

.downlaod-link {
padding: 4px 8px;
}

.table {
margin-bottom: 45px;

Expand Down Expand Up @@ -282,15 +294,16 @@ input:checked + .slider::before {
padding-left: 10px;
align-content: center;

div {
color: #2d6a9f;
}

.download-dropdown {
margin-left: 3px;
}
}

.download-dropdown-trigger {
color: $color-link-dark;
}

.flex {
display: flex;
align-items: center;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,43 @@
<ResponsiveDropdown @renderInPlace={{true}} @buttonStyling={{true}} as |dd| >
<dd.trigger
data-test-download-dropdown
data-analytics-name='Download Dropdown'
aria-label={{t 'institutions.dashboard.download_dropdown_label'}}
local-class='download-dropdown-trigger'
>
<FaIcon @icon='download' />
</dd.trigger>
<dd.content local-class='download-dropdown-content'>
<Button local-class='download-option' {{on 'click' (queue this.downloadCsv dd.close)}}>
<OsfLink
data-test-csv-download-button
data-analytics-name='Download CSV'
local-class='downlaod-link'
{{on 'click' dd.close}}
@target='_blank'
@href={{this.downloadCsvUrl}}
>
{{t 'institutions.dashboard.format_labels.csv'}}
</Button>
<Button local-class='download-option' {{on 'click' (queue this.downloadTsv dd.close)}}>
</OsfLink>
<OsfLink
data-test-tsv-download-button
data-analytics-name='Download TSV'
local-class='downlaod-link'
{{on 'click' dd.close}}
@target='_blank'
@href={{this.downloadTsvUrl}}
>
{{t 'institutions.dashboard.format_labels.tsv'}}
</Button>
<Button local-class='download-option' {{on 'click' (queue this.downloadJsonTable dd.close)}}>
{{t 'institutions.dashboard.format_labels.json_table'}}
</Button>
<Button local-class='download-option' {{on 'click' (queue this.downloadJsonDirect dd.close)}}>
{{t 'institutions.dashboard.format_labels.json_direct'}}
</Button>
</OsfLink>
<OsfLink
data-test-json-download-button
data-analytics-name='Download JSON'
local-class='downlaod-link'
{{on 'click' dd.close}}
@target='_blank'
@href={{this.downloadJsonUrl}}
>
{{t 'institutions.dashboard.format_labels.json'}}
</OsfLink>
</dd.content>
</ResponsiveDropdown>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import { setupIntl } from 'ember-intl/test-support';
import { setupRenderingTest } from 'ember-qunit';
import { TestContext } from 'ember-test-helpers';
import { module, test } from 'qunit';
import Service from '@ember/service';
const featuresStub = Service.extend({
isEnabled: () => true,
});

import { OsfLinkRouterStub } from 'ember-osf-web/tests/integration/helpers/osf-link-router-stub';

Expand All @@ -14,6 +18,7 @@ module('Integration | institutions | dashboard | -components | object-list', hoo
setupIntl(hooks);

hooks.beforeEach(function(this: TestContext) {
this.owner.register('service:features', featuresStub);
this.owner.unregister('service:router');
this.owner.register('service:router', OsfLinkRouterStub);
const columns = [
Expand Down Expand Up @@ -81,6 +86,12 @@ module('Integration | institutions | dashboard | -components | object-list', hoo

// The table data is not blatantly incorrect
assert.dom('[data-test-object-table-body-row]').exists({ count: 10 }, 'There are 10 rows');

// Download buttons are present
await click('[data-test-download-dropdown]');
assert.dom('[data-test-download-csv-link]').exists('CSV download link exists');
assert.dom('[data-test-download-tsv-link]').exists('TSV download link exists');
assert.dom('[data-test-download-json-link]').exists('JSON download link exists');
});

test('the table supports filtering', async function(assert) {
Expand Down
34 changes: 34 additions & 0 deletions app/institutions/dashboard/-components/object-list/component.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import Features from 'ember-feature-flags/services/features';

import IndexCardSearchModel from 'ember-osf-web/models/index-card-search';
import InstitutionModel from 'ember-osf-web/models/institution';
import { SuggestedFilterOperators } from 'ember-osf-web/models/related-property-path';
import SearchResultModel from 'ember-osf-web/models/search-result';
import { Filter } from 'osf-components/components/search-page/component';
import config from 'ember-osf-web/config/environment';

const shareDownloadFlag = config.featureFlagNames.shareDownload;

interface Column {
name: string;
Expand Down Expand Up @@ -36,6 +42,7 @@ interface InstitutionalObjectListArgs {
}

export default class InstitutionalObjectList extends Component<InstitutionalObjectListArgs> {
@service features!: Features;
@tracked activeFilters: Filter[] = [];
@tracked page = '';
@tracked sort = '-dateModified';
Expand Down Expand Up @@ -73,6 +80,33 @@ export default class InstitutionalObjectList extends Component<InstitutionalObje
};
}

get showDownloadButtons() {
return this.features.isEnabled(shareDownloadFlag);
}

downloadUrl(cardSearch: IndexCardSearchModel, format: string) {
if (!cardSearch.links.self) {
return '';
}
const cardSearchUrl = new URL((cardSearch.links.self as string));
cardSearchUrl.searchParams.set('page[size]', '10000');
cardSearchUrl.searchParams.set('acceptMediatype', format);
cardSearchUrl.searchParams.set('withFileName', `${this.args.objectType}-search-results`);
return cardSearchUrl.toString();
}

downloadCsvUrl(cardSearch: IndexCardSearchModel) {
return this.downloadUrl(cardSearch, 'text/csv');
}

downloadTsvUrl(cardSearch: IndexCardSearchModel) {
return this.downloadUrl(cardSearch, 'text/tab-separated-values');
}

downloadJsonUrl(cardSearch: IndexCardSearchModel) {
return this.downloadUrl(cardSearch, 'application/json');
}

@action
updateVisibleColumns() {
this.visibleColumns = [...this.dirtyVisibleColumns];
Expand Down
12 changes: 12 additions & 0 deletions app/institutions/dashboard/-components/object-list/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,15 @@
display: inline-flex;
padding-left: 10px;
}

.download-dropdown-content {
display: flex;
flex-direction: column;
align-items: flex-start;
border: 1px solid $color-border-gray;
width: max-content;
}

.download-link {
padding: 4px 8px;
}
64 changes: 42 additions & 22 deletions app/institutions/dashboard/-components/object-list/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -86,29 +86,49 @@ as |list|>
</OsfLink>
</div>
{{/if}}
<ResponsiveDropdown @renderInPlace={{true}} @buttonStyling={{true}} as |dd| >
<dd.trigger
data-test-download-dropdown
aria-label={{t 'institutions.dashboard.download_dropdown_label'}}
local-class='download-dropdown-trigger'
>
<FaIcon @icon='download' />
</dd.trigger>
<dd.content local-class='download-dropdown-content'>
<Button
local-class='download-option'
{{on 'click' (queue this.downloadCsv dd.close)}}
{{#if this.showDownloadButtons}}
<ResponsiveDropdown @renderInPlace={{true}} @buttonStyling={{true}} as |dd| >
<dd.trigger
data-test-download-dropdown
aria-label={{t 'institutions.dashboard.download_dropdown_label'}}
local-class='download-dropdown-trigger'
>
{{t 'institutions.dashboard.format_labels.csv'}}
</Button>
<Button
local-class='download-option'
{{on 'click' (queue this.downloadTsv dd.close)}}
>
{{t 'institutions.dashboard.format_labels.tsv'}}
</Button>
</dd.content>
</ResponsiveDropdown>
<FaIcon @icon='download' />
</dd.trigger>
<dd.content local-class='download-dropdown-content'>
<OsfLink
data-test-download-csv-link
data-analytics-name='Download CSV'
local-class='download-link'
{{on 'click' dd.close}}
@href={{call (fn (action this.downloadCsvUrl list.latestIndexCardSearch))}}
@target='_blank'
>
{{t 'institutions.dashboard.format_labels.csv'}}
</OsfLink>
<OsfLink
data-test-download-tsv-link
data-analytics-name='Download TSV'
local-class='download-link'
{{on 'click' dd.close}}
@href={{call (fn (action this.downloadTsvUrl list.latestIndexCardSearch))}}
@target='_blank'
>
{{t 'institutions.dashboard.format_labels.tsv'}}
</OsfLink>
<OsfLink
data-test-download-json-link
data-analytics-name='Download JSON'
local-class='download-link'
{{on 'click' dd.close}}
@href={{call (fn (action this.downloadJsonUrl list.latestIndexCardSearch))}}
@target='_blank'
>
{{t 'institutions.dashboard.format_labels.json'}}
</OsfLink>
</dd.content>
</ResponsiveDropdown>
{{/if}}
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit a0fe50f

Please sign in to comment.