Skip to content

Commit

Permalink
Merge branch 'release/23.10.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
adlius committed Aug 28, 2023
2 parents 6a0a8d3 + a8a0c87 commit 57a6790
Show file tree
Hide file tree
Showing 119 changed files with 4,490 additions and 618 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [23.10.0] - 2023-08-28
### Added
- Added search improvement routes and related components

## [23.09.0] - 2023-08-16
### Changed
- Added Google Tag Manager
Expand Down Expand Up @@ -1936,6 +1940,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Added
- Quick Files

[23.10.0]: https://github.com/CenterForOpenScience/ember-osf-web/releases/tag/23.10.0
[23.09.0]: https://github.com/CenterForOpenScience/ember-osf-web/releases/tag/23.09.0
[23.08.0]: https://github.com/CenterForOpenScience/ember-osf-web/releases/tag/23.08.0
[23.07.0]: https://github.com/CenterForOpenScience/ember-osf-web/releases/tag/23.07.0
Expand Down
12 changes: 12 additions & 0 deletions app/adapters/index-card-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import ShareAdapter from './share-adapter';
export default class IndexCardSearchAdapter extends ShareAdapter {
pathForType() {
return 'index-card-search';
}
}

declare module 'ember-data/types/registries/adapter' {
export default interface AdapterRegistry {
'index-card-search': IndexCardSearchAdapter;
} // eslint-disable-line semi
}
13 changes: 13 additions & 0 deletions app/adapters/index-card.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ShareAdapter from './share-adapter';

export default class IndexCardAdapter extends ShareAdapter {
pathForType() {
return 'index-card';
}
}

declare module 'ember-data/types/registries/adapter' {
export default interface AdapterRegistry {
'index-card': IndexCardAdapter;
} // eslint-disable-line semi
}
13 changes: 13 additions & 0 deletions app/adapters/index-value-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ShareAdapter from './share-adapter';

export default class IndexValueSearchAdapter extends ShareAdapter {
pathForType() {
return 'index-value-search';
}
}

declare module 'ember-data/types/registries/adapter' {
export default interface AdapterRegistry {
'index-value-search': IndexValueSearchAdapter;
} // eslint-disable-line semi
}
10 changes: 10 additions & 0 deletions app/adapters/related-property-path.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import ShareAdapter from './share-adapter';

export default class RelatedPropertyPathAdapter extends ShareAdapter {
}

declare module 'ember-data/types/registries/adapter' {
export default interface AdapterRegistry {
'related-property-path': RelatedPropertyPathAdapter;
} // eslint-disable-line semi
}
10 changes: 10 additions & 0 deletions app/adapters/search-result.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import ShareAdapter from './share-adapter';

export default class SearchResultAdapter extends ShareAdapter {
}

declare module 'ember-data/types/registries/adapter' {
export default interface AdapterRegistry {
'search-result': SearchResultAdapter;
} // eslint-disable-line semi
}
7 changes: 7 additions & 0 deletions app/adapters/share-adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import JSONAPIAdapter from '@ember-data/adapter/json-api';
import config from 'ember-get-config';

export default class ShareAdapter extends JSONAPIAdapter {
host = config.OSF.shareBaseUrl.replace(/\/$/, ''); // Remove trailing slash to avoid // in URLs
namespace = 'api/v3';
}
1 change: 1 addition & 0 deletions app/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ const App = Application.extend({
'osf-router',
],
externalRoutes: {
search: 'search',
'guid-registration': 'guid-registration',
'guid-registration.analytics': 'guid-registration.analytics',
'guid-registration.forks': 'guid-registration.forks',
Expand Down
2 changes: 1 addition & 1 deletion app/dashboard/template.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@
<OsfLink
data-analytics-name='noteworthy_search'
local-class='btn btn-default'
@href='/search/?q=*'
@route='search'
>
{{t 'dashboard.noteworthy.search_more'}}
</OsfLink>
Expand Down
40 changes: 40 additions & 0 deletions app/helpers/get-localized-property.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Helper from '@ember/component/helper';
import { inject as service } from '@ember/service';
import IntlService from 'ember-intl/services/intl';

import { LanguageText } from 'ember-osf-web/models/index-card';

/**
* This helper is used to get a locale-appropriate string for a property from a metadata hash.
* It is used to fetch metadata fields from a index-card's resourceMetadata attribute, but can be used for any
* hash that contains an array of LangaugeText objects.
* If the property is not found, the first value in the array is returned, or if the property is found,
* but there is no locale-appropriate value, the first value in the array is returned.
*
* @example
* ```handlebars
* {{get-localized-property indexCard.resourceMetadata 'title'}}
* ```
* where `indexCard` is an index-card model instance.
* @class get-localized-property
* @param {Object} metadataHash The metadata hash to search for the property
* @param {String} propertyName The name of the property to search for
* @return {String} The locale-appropriate string or the first value in the array or 'Not provided' message
*/
export default class GetLocalizedPropertyHelper extends Helper {
@service intl!: IntlService;

compute([metadataHash, propertyName]: [Record<string, LanguageText[]>, string]): string {
const locale = this.intl.locale;
const valueOptions = metadataHash?.[propertyName];
if (!metadataHash || !valueOptions || valueOptions.length === 0) {
return this.intl.t('helpers.get-localized-property.not-provided');
}

const index = valueOptions.findIndex((valueOption: LanguageText) => valueOption['@language'] === locale);
if (index === -1) {
return valueOptions[0]['@value'];
}
return valueOptions[index]['@value'];
}
}
7 changes: 3 additions & 4 deletions app/home/-components/hero-banner/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import { tagName } from '@ember-decorators/component';
import Component from '@ember/component';
import { action } from '@ember/object';
import { alias } from '@ember/object/computed';
import RouterService from '@ember/routing/router-service';
import { inject as service } from '@ember/service';
import { camelize } from '@ember/string';
import Features from 'ember-feature-flags/services/features';
import config from 'ember-get-config';

import { serviceLinks } from 'ember-osf-web/const/service-links';

import { layout } from 'ember-osf-web/decorators/component';

import styles from './styles';
Expand All @@ -20,13 +19,13 @@ const { featureFlagNames: { ABTesting } } = config;
@tagName('')
export default class HomeHeroBanner extends Component {
@service features!: Features;
@service router!: RouterService;

@alias(`features.${camelize(ABTesting.homePageHeroTextVersionB)}`)
shouldShowVersionB!: boolean;

@action
search(query: string) {
const { search } = serviceLinks;
window.location.href = `${search}?q=${query}&page=1`;
this.router.transitionTo('search', { queryParams: { q: query }});
}
}
2 changes: 1 addition & 1 deletion app/institutions/dashboard/controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { alias } from '@ember/object/computed';
import Controller from '@ember/controller';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import { inject as service } from '@ember/service';

import { InstitutionsDashboardModel } from 'ember-osf-web/institutions/dashboard/route';
Expand Down
31 changes: 31 additions & 0 deletions app/institutions/discover/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import CurrentUser from 'ember-osf-web/services/current-user';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import pathJoin from 'ember-osf-web/utils/path-join';
import config from 'ember-get-config';
import { OnSearchParams, ResourceTypeFilterValue } from 'osf-components/components/search-page/component';

export default class InstitutionDiscoverController extends Controller {
@service currentUser!: CurrentUser;

@tracked cardSearchText?: string = '';
@tracked sort?: string = '-relevance';
@tracked resourceType?: ResourceTypeFilterValue | null = null;

queryParams = ['cardSearchText', 'page', 'sort', 'resourceType'];

get defaultQueryOptions() {
return {
publisher: pathJoin(config.OSF.url, 'institutions', this.model.id),
};
}

@action
onSearch(queryOptions: OnSearchParams) {
this.cardSearchText = queryOptions.cardSearchText;
this.sort = queryOptions.sort;
this.resourceType = queryOptions.resourceType;
}
}
8 changes: 8 additions & 0 deletions app/institutions/discover/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Route from '@ember/routing/route';
import RouterService from '@ember/routing/router-service';
import { inject as service } from '@ember/service';


export default class InstitutionDiscoverRoute extends Route {
@service router!: RouterService;
}
11 changes: 11 additions & 0 deletions app/institutions/discover/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<SearchPage
@route='search'
@query={{this.q}}
@defaultQueryOptions={{this.defaultQueryOptions}}
@queryParams={{this.queryParams}}
@onSearch={{action this.onSearch}}
@resourceType={{this.resourceType}}
@institution={{this.model}}
@sort={{this.sort}}
@showResourceTypeFilter={{true}}
/>
54 changes: 54 additions & 0 deletions app/models/index-card-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Model, { AsyncHasMany, attr, hasMany } from '@ember-data/model';

import RelatedPropertyPathModel from './related-property-path';
import SearchResultModel from './search-result';

export interface SearchFilter {
propertyPath: string;
filterValue: string[];
filterType?: string;
}

export const ShareMoreThanTenThousand = 'https://share.osf.io/vocab/2023/trove/ten-thousands-and-more';

export default class IndexCardSearchModel extends Model {
@attr('string') cardSearchText!: string;
@attr('array') cardSearchFilters!: SearchFilter[];
@attr('string') totalResultCount!: number | typeof ShareMoreThanTenThousand;

@hasMany('search-result', { inverse: null })
searchResultPage!: AsyncHasMany<SearchResultModel> & SearchResultModel[];

@hasMany('related-property-path', { inverse: null })
relatedProperties!: RelatedPropertyPathModel[];

get firstPageCursor() {
if (this.searchResultPage.links.first?.href) {
const firstPageLinkUrl = new URL(this.searchResultPage.links.first?.href);
return firstPageLinkUrl.searchParams.get('page[cursor]');
}
return null;
}

get prevPageCursor() {
if (this.searchResultPage.links.prev?.href) {
const prevPageLinkUrl = new URL(this.searchResultPage.links.prev?.href);
return prevPageLinkUrl.searchParams.get('page[cursor]');
}
return null;
}

get nextPageCursor() {
if (this.searchResultPage.links.next?.href) {
const nextPageLinkUrl = new URL(this.searchResultPage.links.next?.href);
return nextPageLinkUrl.searchParams.get('page[cursor]');
}
return null;
}
}

declare module 'ember-data/types/registries/model' {
export default interface ModelRegistry {
'index-card-search': IndexCardSearchModel;
} // eslint-disable-line semi
}
53 changes: 53 additions & 0 deletions app/models/index-card.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { inject as service } from '@ember/service';
import Model, { AsyncHasMany, attr, hasMany } from '@ember-data/model';
import IntlService from 'ember-intl/services/intl';

import GetLocalizedPropertyHelper from 'ember-osf-web/helpers/get-localized-property';
import { getOwner } from '@ember/application';

export interface LanguageText {
'@language': string;
'@value': string;
}

export default class IndexCardModel extends Model {
@service intl!: IntlService;

@attr('array') resourceType!: string[];
@attr('array') resourceIdentifier!: string[];
// TODO: can we add a type for resourceMetadata?
@attr('object') resourceMetadata!: any;

@hasMany('index-card', { inverse: null })
relatedRecordSet!: AsyncHasMany<IndexCardModel> & IndexCardModel[];

getLocalizedString = new GetLocalizedPropertyHelper(getOwner(this));

get resourceId() {
return this.resourceIdentifier[0];
}

get label() {
const possibleLabelKeys = ['displayLabel', 'name', 'title'];
for (const key of possibleLabelKeys) {
if (this.resourceMetadata[key]) {
const label = this.getLocalizedString.compute([this.resourceMetadata, key]);
// TODO: Get rid of this special casing once we have a decision on how BE should represents OSF provider
if (label === 'OSF') {
return 'OSF Projects';
}
if (label === 'Open Science Framework') {
return 'OSF Preprints';
}
return label;
}
}
return '';
}
}

declare module 'ember-data/types/registries/model' {
export default interface ModelRegistry {
'index-card': IndexCardModel;
} // eslint-disable-line semi
}
21 changes: 21 additions & 0 deletions app/models/index-value-search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Model, { AsyncHasMany, attr, hasMany } from '@ember-data/model';

import { SearchFilter } from './index-card-search';
import SearchResultModel from './search-result';

export default class IndexValueSearchModel extends Model {
@attr('string') valueSearchText!: string;
@attr('string') valueSearchPropertyPath!: string;
@attr('string') cardSearchText!: string;
@attr('array') cardSearchFilter!: SearchFilter[];
@attr('number') totalResultCount!: number;

@hasMany('search-result', { inverse: null })
searchResultPage!: AsyncHasMany<SearchResultModel> & SearchResultModel[];
}

declare module 'ember-data/types/registries/model' {
export default interface ModelRegistry {
'index-value-search': IndexValueSearchModel;
} // eslint-disable-line semi
}
Loading

0 comments on commit 57a6790

Please sign in to comment.