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

feat: add record counts to topics/times tables #2262

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
50 changes: 41 additions & 9 deletions packages/portal/src/cachers/collections/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { createEuropeanaApiClient } from '../utils.js';
import { getLabelledSlug } from '../../plugins/europeana/utils.js';

let axiosClient;
let entityApiClient;
let recordApiClient;

const pageSize = 100;

export const countEntities = async(params = {}, config = {}) => {
axiosClient = createEuropeanaApiClient(config.europeana?.apis?.entity);
entityApiClient = createEuropeanaApiClient(config.europeana?.apis?.entity);

const response = await axiosClient.get('/search', {
const response = await entityApiClient.get('/search', {
params: {
...axiosClient.defaults.config,
...entityApiClient.defaults.config,
query: '*:*',
scope: 'europeana',
pageSize: 0,
Expand All @@ -21,9 +22,9 @@ export const countEntities = async(params = {}, config = {}) => {
};

const pageOfEntityResults = (page, params = {}) => {
return axiosClient.get('/search', {
return entityApiClient.get('/search', {
params: {
...axiosClient.defaults.config,
...entityApiClient.defaults.config,
query: '*:*',
scope: 'europeana',
sort: 'id',
Expand Down Expand Up @@ -56,8 +57,39 @@ const allEntityResults = async(params) => {
return allResults;
};

export default (params = {}, config = {}) => {
axiosClient = createEuropeanaApiClient(config.europeana?.apis?.entity);
const getRecordCounts = async(recordLinkField) => {
const params = {
profile: 'facets',
query: `${recordLinkField}:*data.europeana.eu*`,
facet: recordLinkField,
[`f.${recordLinkField}.facet.limit`]: 10000,
rows: 0
};
const response = await recordApiClient.get('/search.json', { params });
return response.data?.facets?.[0]?.fields || [];
};

const withRecordCounts = async(entities, recordLinkField) => {
const recordCounts = await getRecordCounts(recordLinkField);

for (const entity of entities) {
// Add recordCount
const entityId = entity.id;
const entityWithCount = recordCounts.find(facet => facet.label === entityId);
const recordCount = entityWithCount?.count || 0;
entity.recordCount = recordCount;
}

return allEntityResults(params);
return entities;
};

export default async(params = {}, config = {}, options = {}) => {
entityApiClient = createEuropeanaApiClient(config.europeana?.apis?.entity);
recordApiClient = createEuropeanaApiClient(config.europeana?.apis?.record);

let results = await allEntityResults(params);
if (options.recordCounts) {
results = await withRecordCounts(results, options.recordCounts);
}
return results;
};
43 changes: 10 additions & 33 deletions packages/portal/src/cachers/collections/organisations.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,20 @@ import uniq from 'lodash/uniq.js';
import countryCodes from 'i18n-iso-countries';
import localeCodes from '../../plugins/i18n/codes.js';

const PICK = ['slug', 'recordCount', 'prefLabel', 'countryPrefLabel'];
const LOCALISE = 'countryPrefLabel';
const PICK = ['slug', 'recordCount', 'prefLabel', 'countryPrefLabel'];

let axiosClient;
let axiosClientEntity;

async function getRecordCounts() {
const params = {
profile: 'facets',
query: 'foaf_organization:*data.europeana.eu*',
facet: 'foaf_organization',
['f.foaf_organization.facet.limit']: 10000,
rows: 0
};
const response = await axiosClient.get('/search.json', { params });
return response.data?.facets?.[0]?.fields || [];
}
let entityApiClient;

async function getCountryPrefLabel(entityUrl) {
const response = await axiosClientEntity.get(entityUrl);
const response = await entityApiClient.get(entityUrl);
return response.data.prefLabel;
}

const data = async(config = {}) => {
const organisationData = await baseData({ type: 'organization' }, config);

axiosClient = createEuropeanaApiClient(config.europeana?.apis?.record);
axiosClientEntity = createEuropeanaApiClient(config.europeana?.apis?.entity);
const organisationData = await baseData({ type: 'organization' }, config, { recordCounts: 'foaf_organization' });

const recordCounts = await getRecordCounts();
entityApiClient = createEuropeanaApiClient(config.europeana?.apis?.entity);

// Get array with all unique countries to only have to request prefLabels once
const organisationCountries = uniq(organisationData.map(organisation => organisation.country));
Expand All @@ -60,19 +44,12 @@ const data = async(config = {}) => {
}
}

return organisationData.map(
organisation => {
// Add recordCount
const organisationId = organisation.id;
const organisationWithCount = recordCounts.find(facet => facet.label === organisationId);
const recordCount = organisationWithCount?.count || 0;
organisation.recordCount = recordCount;

// Add countryPrefLabel with langmap prefLabel
organisation.countryPrefLabel = organisationCountriesPrefLabels[organisation.country] || organisation.country;
return organisationData.map((organisation) => {
// Add countryPrefLabel with langmap prefLabel
organisation.countryPrefLabel = organisationCountriesPrefLabels[organisation.country] || organisation.country;

return organisation;
});
return organisation;
});
};

export {
Expand Down
4 changes: 2 additions & 2 deletions packages/portal/src/cachers/collections/times.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import baseData from './index.js';

const PICK = ['slug', 'prefLabel'];
const PICK = ['slug', 'prefLabel', 'recordCount'];
const LOCALISE = 'prefLabel';
const SORT = 'prefLabel';

const data = (config = {}) => baseData({ type: 'timespan' }, config);
const data = (config = {}) => baseData({ type: 'timespan' }, config, { recordCounts: 'edm_timespan' });

export {
data,
Expand Down
4 changes: 2 additions & 2 deletions packages/portal/src/cachers/collections/topics.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import baseData from './index.js';

const PICK = ['slug', 'prefLabel'];
const PICK = ['slug', 'prefLabel', 'recordCount'];
const LOCALISE = 'prefLabel';
const SORT = 'prefLabel';

const data = (config = {}) => baseData({ type: 'concept' }, config);
const data = (config = {}) => baseData({ type: 'concept' }, config, { recordCounts: 'skos_concept' });

export {
data,
Expand Down
61 changes: 32 additions & 29 deletions packages/portal/src/components/entity/EntityTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
</SmartLink>
</template>
<template
v-if="type === 'organisations'"
v-if="hasField('recordCount')"
#cell(recordCount)="data"
>
<span>
Expand All @@ -88,7 +88,7 @@
</b-button>
</template>
<template
v-if="type === 'organisations'"
v-if="hasField('countryPrefLabel')"
#row-details="row"
>
<span>{{ row.item.countryPrefLabel }}</span>
Expand Down Expand Up @@ -137,30 +137,6 @@
return {
collections: null,
filter: this.$route?.query?.filter || null,
fields: [
{
key: 'prefLabel',
sortable: true,
label: this.$t('pages.collections.table.name'),
class: 'table-name-cell'
},
this.type === 'organisations' && {
key: 'countryPrefLabel',
sortable: true,
label: this.$t('pages.collections.table.country'),
class: 'text-center d-none d-md-table-cell'
},
this.type === 'organisations' && {
key: 'recordCount',
sortable: true,
label: this.$t('pages.collections.table.items'),
class: 'text-right'
},
this.type === 'organisations' && {
key: 'showDetails',
class: 'table-toggle-cell d-md-none'
}
],
typeSingular: this.type.slice(0, -1),
totalResults: this.collections?.length || 0,
perPage: 40
Expand All @@ -173,10 +149,8 @@
let collections = response.data[this.cacheKey];
if (this.type === 'organisations') {
collections = collections.map(this.organisationData);
this.collections = collections; // Do not freeze as _showDetails prop needs to be reactive for toggling the details display on small screens
} else {
this.collections = collections.map(Object.freeze);
}
this.collections = collections; // Do not freeze as _showDetails prop needs to be reactive for toggling the details display on small screens
} catch (e) {
// TODO: set fetch state error from message
console.error({ statusCode: 500, message: e.toString() });
Expand All @@ -195,6 +169,32 @@
currentPage() {
return Number(this.$route?.query?.page) || 1;
},
fields() {
return [
{
key: 'prefLabel',
sortable: true,
label: this.$t('pages.collections.table.name'),
class: 'table-name-cell'
},
this.type === 'organisations' && {
key: 'countryPrefLabel',
sortable: true,
label: this.$t('pages.collections.table.country'),
class: 'text-center d-none d-md-table-cell'
},
(this.collections?.[0]?.recordCount !== undefined) && {
key: 'recordCount',
sortable: true,
label: this.$t('pages.collections.table.items'),
class: 'text-right'
},
this.type === 'organisations' && {
key: 'showDetails',
class: 'table-toggle-cell d-md-none'
}
];
},
sortBy: {
get() {
return this.sort[0] || 'prefLabel';
Expand Down Expand Up @@ -233,6 +233,9 @@
},

methods: {
hasField(name) {
return this.fields.some((field) => field.key === name);
},
organisationData(org) {
const nativeName = this.organizationEntityNativeName({ ...org, type: 'Organization' });
const nativeNameLangMapValue = langMapValueForLocale(nativeName, this.$i18n.locale);
Expand Down
4 changes: 2 additions & 2 deletions packages/portal/tests/unit/cachers/collections/times.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ describe('@/cachers/collections/times', () => {
sinon.resetHistory();
});

it('picks slug and prefLabel', () => {
expect(cacher.PICK).toEqual(['slug', 'prefLabel']);
it('picks slug and prefLabel and recordCount', () => {
expect(cacher.PICK).toEqual(['slug', 'prefLabel', 'recordCount']);
});

it('localises prefLabel', () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/portal/tests/unit/cachers/collections/topics.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ describe('@/cachers/collections/topics', () => {
sinon.resetHistory();
});

it('picks slug and prefLabel', () => {
expect(cacher.PICK).toEqual(['slug', 'prefLabel']);
it('picks slug and prefLabel and recordCount', () => {
expect(cacher.PICK).toEqual(['slug', 'prefLabel', 'recordCount']);
});

it('localises prefLabel', () => {
Expand Down
11 changes: 7 additions & 4 deletions packages/portal/tests/unit/components/entity/EntityTable.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const factory = (propsData = { type: 'organisations' }, fetchState = { error: fa

const middlewarePath = '/_api/cache/en/collections/organisations';
const collections = [
{ slug: '001-museum', prefLabel: { de: 'museum', en: 'museum' }, countryPrefLabel: 'Deutschland' },
{ slug: '002-library', prefLabel: { nl: 'bibliotheek', en: 'library' }, countryPrefLabel: 'Nederland' }
{ slug: '001-museum', prefLabel: { de: 'museum', en: 'museum' }, countryPrefLabel: 'Deutschland', recordCount: 1 },
{ slug: '002-library', prefLabel: { nl: 'bibliotheek', en: 'library' }, countryPrefLabel: 'Nederland', recordCount: 2 }
];

const organisations = [
Expand All @@ -40,15 +40,17 @@ const organisations = [
prefLabelLang: 'de',
altLabel: 'museum',
altLabelLang: null,
countryPrefLabel: 'Deutschland'
countryPrefLabel: 'Deutschland',
recordCount: 1
},
{
slug: '002-library',
prefLabel: 'bibliotheek',
prefLabelLang: 'nl',
altLabel: 'library',
altLabelLang: null,
countryPrefLabel: 'Nederland'
countryPrefLabel: 'Nederland',
recordCount: 2
}
];

Expand Down Expand Up @@ -188,6 +190,7 @@ describe('components/entity/EntityTable', () => {
describe('when the table is sorted', () => {
it('updates the route query', async() => {
const wrapper = factory();
await wrapper.setData({ collections });
sinon.spy(wrapper.vm, 'updateRouteQuery');

const recordCountTh = wrapper.find('[aria-colindex="3"]');
Expand Down
Loading