diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000000..ab52ebc73c4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "public/assets/osf-assets"] + path = public/assets/osf-assets + url = https://github.com/CenterForOpenScience/osf-assets.git diff --git a/app/app.ts b/app/app.ts index 18f5dc368c2..5d227c04cc7 100644 --- a/app/app.ts +++ b/app/app.ts @@ -18,6 +18,7 @@ const App = Application.extend({ 'i18n', 'session', 'store', + 'theme', 'router', ], }, diff --git a/app/application/controller.ts b/app/application/controller.ts index f9c5a71fe1f..4fd8cf9a194 100644 --- a/app/application/controller.ts +++ b/app/application/controller.ts @@ -5,12 +5,14 @@ import Controller from '@ember/controller'; import { Registry as Services } from '@ember/service'; import config from 'ember-get-config'; import CurrentUser from 'ember-osf-web/services/current-user'; +import Theme from 'ember-osf-web/services/theme'; import pathJoin from 'ember-osf-web/utils/path-join'; import $ from 'jquery'; export default class Application extends Controller { @service currentUser!: CurrentUser; @service router!: Services['router']; + @service theme!: Theme; secondaryNavbarId = config.secondaryNavbarId; signupUrl = `${pathJoin(config.OSF.url, 'register')}?${$.param({ next: window.location.href })}`; diff --git a/app/application/template.hbs b/app/application/template.hbs index b24a2401c74..17a05f7b975 100644 --- a/app/application/template.hbs +++ b/app/application/template.hbs @@ -2,7 +2,11 @@ {{title (t 'general.OSF')}}
{{#unless disableHeaders}} - {{osf-navbar signupUrl=signupUrl loginAction=(action 'login')}} + {{#if theme.isProvider}} + {{branded-navbar}} + {{else}} + {{osf-navbar signupUrl=signupUrl loginAction=(action 'login')}} + {{/if}}
{{maintenance-banner}} {{status-banner}} diff --git a/app/const/service-links.ts b/app/const/service-links.ts index bd183c047ad..857d82ae638 100644 --- a/app/const/service-links.ts +++ b/app/const/service-links.ts @@ -22,6 +22,7 @@ const serviceLinks = { settings: `${osfUrl}settings/`, reviewsHome: `${osfUrl}reviews/`, institutionsLanding: `${osfUrl}institutions/`, + collectionsHome: `${osfUrl}collections/`, }; const osfServices = [ @@ -46,6 +47,10 @@ const osfServices = [ url: serviceLinks.institutionsLanding, flag: navigation.institutions, }, + { + name: 'COLLECTIONS', + url: serviceLinks.collectionsHome, + }, ]; export { diff --git a/app/locales/en/translations.ts b/app/locales/en/translations.ts index 610a1855152..a40972da911 100644 --- a/app/locales/en/translations.ts +++ b/app/locales/en/translations.ts @@ -564,6 +564,19 @@ export default { collections: { index: { title: 'Collections', + services_heading: 'Collection Services', + services_paragraph: 'Leading collection service providers use this open source infrastructure to support their communities.', + service_bottom: { + p1: 'Create your own branded collection service backed by the OSF.', + div: { + line1: 'Check out the', + linkText1: 'open source code', + line2: 'and the', + linkText2: 'requirements and road map', + line3: '. Input welcome!', + }, + contact: 'Contact us', + }, }, provider: { title: 'Provider', @@ -572,6 +585,7 @@ export default { title: 'Discover', search_heading: 'Collections Search', search_placeholder: 'Search collections', + other_repositories: 'Other collections', }, submit: { title: 'Submit', @@ -770,6 +784,8 @@ export default { main: { providers: 'Providers', subject: 'Subject', + status: 'Status', + type: 'Type', }, relevance: 'Relevance', sort_oldest_newest: 'Modified Date (oldest to newest)', diff --git a/app/models/collection-provider.ts b/app/models/collection-provider.ts index 5972fa28ec7..67ce039515c 100644 --- a/app/models/collection-provider.ts +++ b/app/models/collection-provider.ts @@ -1,48 +1,11 @@ -import { attr, hasMany } from '@ember-decorators/data'; -import { alias } from '@ember-decorators/object/computed'; +import { belongsTo, hasMany } from '@ember-decorators/data'; import DS from 'ember-data'; import Collection from './collection'; -import License from './license'; -import OsfModel from './osf-model'; -import Taxonomy from './taxonomy'; +import Provider from './provider'; -export default class CollectionProvider extends OsfModel { - @attr('fixstring') name!: string; // eslint-disable-line no-restricted-globals - @attr('fixstring') description!: string; - @attr('string') domain!: string; - @attr('boolean') domainRedirectEnabled!: boolean; - @attr('fixstring') example!: string; - @attr('string') advisoryBoard!: string; - @attr('fixstring') emailSupport!: string; - // @attr('array') subjectsAcceptable!: string[]; - @attr('string') footerLinks!: string; - @attr('boolean') allowSubmissions!: boolean; - @attr('boolean') allowCommenting!: boolean; - @attr('string') facebookAppId!: string; - // @attr('array') additionalProviders!: string[]; - // @attr('string') shareSource!: string; - // @attr('string') preprintWord!: string; - - // // Reviews settings - // @attr('array') permissions!: string[]; - // @attr('string') reviewsWorkflow!: string | null; - // @attr('boolean', { allowNull: true }) reviewsCommentsPrivate!: boolean | null; - // @attr('boolean', { allowNull: true }) reviewsCommentsAnonymous!: boolean | null; - - // Relationships - @hasMany('taxonomy') taxonomies!: DS.PromiseManyArray; - @hasMany('taxonomy') highlightedTaxonomies!: DS.PromiseManyArray; +export default class CollectionProvider extends Provider { + @belongsTo('collection') primaryCollection!: DS.PromiseObject & Collection; @hasMany('collection', { inverse: 'provider' }) collections!: DS.PromiseManyArray; - @hasMany('license', { inverse: null }) licensesAcceptable!: DS.PromiseManyArray; - - // @alias('links.relationships.preprints.links.related.meta') - // reviewableStatusCounts!: any; - - // @alias('links.relationships.highlighted_taxonomies.links.related.meta.has_highlighted_subjects') - // hasHighlightedSubjects!: boolean; - - @alias('relationships.primary_collection.data.id') - primaryCollection!: string; } declare module 'ember-data' { diff --git a/app/models/collection.ts b/app/models/collection.ts index 3a889028f24..93c78736bf4 100644 --- a/app/models/collection.ts +++ b/app/models/collection.ts @@ -5,8 +5,6 @@ import Node from 'ember-osf-web/models/node'; import Registration from 'ember-osf-web/models/registration'; import OsfModel from './osf-model'; -type statusChoice = 'good'; - /** * @module ember-osf-web * @submodule models @@ -25,7 +23,7 @@ export default class Collection extends OsfModel { @attr('boolean') isPromoted!: boolean; @attr('boolean') isPublic!: boolean; @attr('array') collectedTypeChoices!: Array<'node' | 'preprint' | 'collection' | 'registration'>; - @attr('array') statusChoices!: statusChoice[]; + @attr('array') statusChoices!: string[]; @belongsTo('collection-provider', { inverse: 'collections' }) provider!: DS.PromiseObject & CollectionProvider; diff --git a/app/models/preprint-provider.ts b/app/models/preprint-provider.ts index 0dd9e5273e0..9ae10508c05 100644 --- a/app/models/preprint-provider.ts +++ b/app/models/preprint-provider.ts @@ -1,22 +1,12 @@ import { attr, hasMany } from '@ember-decorators/data'; import { alias } from '@ember-decorators/object/computed'; import DS from 'ember-data'; -import License from './license'; -import OsfModel from './osf-model'; +// import License from './license'; import Preprint from './preprint'; -import Taxonomy from './taxonomy'; +import Provider from './provider'; -export default class PreprintProvider extends OsfModel { - @attr('fixstring') name!: string; // eslint-disable-line no-restricted-globals - @attr('fixstring') description!: string; - @attr('string') domain!: string; - @attr('boolean') domainRedirectEnabled!: boolean; - @attr('fixstring') example!: string; - @attr('string') advisoryBoard!: string; - @attr('fixstring') emailSupport!: string; +export default class PreprintProvider extends Provider { @attr('array') subjectsAcceptable!: string[]; - @attr('string') footerLinks!: string; - @attr('boolean') allowSubmissions!: boolean; @attr('array') additionalProviders!: string[]; @attr('string') shareSource!: string; @attr('string') preprintWord!: string; @@ -28,10 +18,7 @@ export default class PreprintProvider extends OsfModel { @attr('boolean', { allowNull: true }) reviewsCommentsAnonymous!: boolean | null; // Relationships - @hasMany('taxonomy') taxonomies!: DS.PromiseManyArray; - @hasMany('taxonomy') highlightedTaxonomies!: DS.PromiseManyArray; @hasMany('preprint', { inverse: 'provider' }) preprints!: DS.PromiseManyArray; - @hasMany('license', { inverse: null }) licensesAcceptable!: DS.PromiseManyArray; @alias('links.relationships.preprints.links.related.meta') reviewableStatusCounts!: any; diff --git a/app/models/provider.ts b/app/models/provider.ts new file mode 100644 index 00000000000..da7aa87cfef --- /dev/null +++ b/app/models/provider.ts @@ -0,0 +1,40 @@ +import { attr, hasMany } from '@ember-decorators/data'; +import DS from 'ember-data'; +import License from './license'; +import OsfModel from './osf-model'; +import Taxonomy from './taxonomy'; + +/* eslint-disable camelcase */ + +interface Assets { + favicon: string; + powered_by_share: string; + sharing: string; + square_color_no_transparent: string; + square_color_transparent: string; + style: string; + wide_black: string; + wide_color: string; + wide_white: string; +} + +/* eslint-enable camelcase */ + +export default abstract class Provider extends OsfModel { + @attr('fixstring') name!: string; // eslint-disable-line no-restricted-globals + @attr('fixstring') description!: string; + @attr('string') advisoryBoard!: string; + @attr('fixstring') example!: string; + @attr('string') domain!: string; + @attr('boolean') domainRedirectEnabled!: boolean; + @attr('fixstring') footerLinks!: string; + @attr('fixstring') emailSupport!: string; + @attr('string') facebookAppId!: string; + @attr('boolean') allowSubmissions!: boolean; + @attr('boolean') allowCommenting!: boolean; + @attr() assets!: Assets; // TODO: camelize in transform + + @hasMany('taxonomy') taxonomies!: DS.PromiseManyArray; + @hasMany('taxonomy') highlightedTaxonomies!: DS.PromiseManyArray; + @hasMany('license', { inverse: null }) licensesAcceptable!: DS.PromiseManyArray; +} diff --git a/lib/collections/addon/services/theme.ts b/app/services/theme.ts similarity index 86% rename from lib/collections/addon/services/theme.ts rename to app/services/theme.ts index 7cb71c357f6..d38df2b1e79 100644 --- a/lib/collections/addon/services/theme.ts +++ b/app/services/theme.ts @@ -1,12 +1,13 @@ import { computed } from '@ember-decorators/object'; import { service } from '@ember-decorators/service'; import Service from '@ember/service'; -import config from 'collections/config/environment'; +// import config from 'ember-default-config'; import DS from 'ember-data'; -import PreprintProvider from 'ember-osf-web/models/preprint-provider'; +import Provider from 'ember-osf-web/models/provider'; import defaultTo from 'ember-osf-web/utils/default-to'; -const { defaultProvider } = config; +// const { defaultProvider } = config; +const defaultProvider = 'osf'; export default class Theme extends Service { @service store!: DS.Store; @@ -23,8 +24,8 @@ export default class Theme extends Service { } @computed('id', 'isProvider') - get provider(): PreprintProvider | null { - const provider = this.store.peekRecord('preprint-provider', this.id); + get provider(): Provider | null { + const provider = this.store.peekRecord('collection-provider', this.id); if (!provider) { return null; diff --git a/lib/app-components/addon/styles/headers.scss b/lib/app-components/addon/styles/headers.scss new file mode 100644 index 00000000000..d3876dfb4c8 --- /dev/null +++ b/lib/app-components/addon/styles/headers.scss @@ -0,0 +1 @@ +// @import '../../../app/styles/variables'; diff --git a/lib/app-components/index.js b/lib/app-components/index.js new file mode 100644 index 00000000000..70232418894 --- /dev/null +++ b/lib/app-components/index.js @@ -0,0 +1,17 @@ +/* eslint-env node */ + +module.exports = { + name: 'app-components', + + isDevelopingAddon() { + return true; + }, + + options: { + cssModules: { + headerModules: [ + 'app-components/styles/headers', + ], + }, + }, +}; diff --git a/lib/app-components/package.json b/lib/app-components/package.json new file mode 100644 index 00000000000..5976784060d --- /dev/null +++ b/lib/app-components/package.json @@ -0,0 +1,22 @@ +{ + "name": "app-components", + "keywords": [ + "ember-addon" + ], + "dependencies": { + "ember-bootstrap": "*", + "ember-bootstrap-datepicker": "*", + "ember-cli-babel": "*", + "ember-cli-htmlbars": "*", + "ember-cli-htmlbars-inline-precompile": "*", + "ember-cli-sass": "*", + "ember-cli-template-lint": "*", + "ember-cli-typescript": "*", + "ember-component-attributes": "*", + "ember-cp-validations": "*", + "ember-css-modules": "*", + "ember-css-modules-sass": "*", + "ember-i18n": "*", + "ember-i18n-inject": "*" + } +} diff --git a/lib/collections/addon/components/discover-page/active-filters/component.ts b/lib/collections/addon/components/discover-page/active-filters/component.ts index e7945fa23e6..7b1f9c8bba2 100644 --- a/lib/collections/addon/components/discover-page/active-filters/component.ts +++ b/lib/collections/addon/components/discover-page/active-filters/component.ts @@ -2,9 +2,8 @@ import { action } from '@ember-decorators/object'; import { service } from '@ember-decorators/service'; import Component from '@ember/component'; import { assert } from '@ember/debug'; -import Theme from 'collections/services/theme'; - import { get } from '@ember/object'; +import Theme from 'ember-osf-web/services/theme'; import { FacetContexts } from '../component'; export default class ActiveFilters extends Component { diff --git a/lib/collections/addon/components/discover-page/active-filters/template.hbs b/lib/collections/addon/components/discover-page/active-filters/template.hbs index a4cc22a41f5..987198e7fc1 100644 --- a/lib/collections/addon/components/discover-page/active-filters/template.hbs +++ b/lib/collections/addon/components/discover-page/active-filters/template.hbs @@ -12,7 +12,7 @@
-{{#each facetContexts.provider.activeFilter as |item|}} +{{#each facetContexts.collection-provider.activeFilter as |item|}} {{filter-replace item filterReplace}} {{#unless theme.isProvider}} @@ -21,7 +21,7 @@ {{/unless}} @@ -40,6 +40,33 @@ {{/each}} +{{#each facetContexts.collected-type.activeFilter as |item|}} + {{!ACTIVE SUBJECT FILTERS}} + + {{item}} + + + + +{{/each}} + +{{#each facetContexts.status.activeFilter as |item|}} + {{!ACTIVE SUBJECT FILTERS}} + + {{item}} + + + + +{{/each}} {{!ACTIVE TYPE FILTERS}} {{!-- {{#each activeFilters.types as |filter|}} diff --git a/lib/collections/addon/components/discover-page/component.ts b/lib/collections/addon/components/discover-page/component.ts index dc83a96e190..35b890d0e29 100644 --- a/lib/collections/addon/components/discover-page/component.ts +++ b/lib/collections/addon/components/discover-page/component.ts @@ -5,12 +5,12 @@ import { assert } from '@ember/debug'; import EmberObject, { setProperties } from '@ember/object'; import { debounce } from '@ember/runloop'; import { camelize } from '@ember/string'; -import Theme from 'collections/services/theme'; import config from 'ember-get-config'; import I18N from 'ember-i18n/services/i18n'; import Contributor from 'ember-osf-web/models/contributor'; import Analytics from 'ember-osf-web/services/analytics'; import CurrentUser from 'ember-osf-web/services/current-user'; +import Theme from 'ember-osf-web/services/theme'; import defaultTo from 'ember-osf-web/utils/default-to'; import eatArgs from 'ember-osf-web/utils/eat-args'; import moment from 'moment'; @@ -149,6 +149,7 @@ interface Hit { export interface FacetContext extends EmberObject { didInit: boolean; activeFilter: any[]; + lockedActiveFilter: any[]; defaultQueryFilters: any[]; currentQueryFilters: any; queryParam: string; @@ -237,6 +238,7 @@ export default class DiscoverPage extends Component.extend({ [component]: { didInit: false, queryParam, + lockedActiveFilter: [], activeFilter, defaultQueryFilters: [], currentQueryFilters: [], @@ -499,66 +501,18 @@ export default class DiscoverPage extends Component.extend({ }, }; - // // Ember-SHARE property. Watches query params in URL and modifies facetStates - // @computed(...filterQueryParams, 'end', 'start') - // get facetStates(): any { - // return { - // ...filterQueryParams.reduce((acc: any, val: keyof DiscoverPage) => ({ ...acc, [val]: this[val] }), {}), - // date: { - // start: this.start, - // end: this.end, - // }, - // }; - // } - - // // Modified when query params in URL change. - // @computed('facetStates') - // get facetStatesArray() { - // return Object.entries(this.facetStates) - // .map(([key, value]) => ({ key, value })); - // } - // Ember-SHARE property. Returns pages of hidden search results. @computed('clampedPages', 'totalPages') get hiddenPages() { return this.totalPages === this.clampedPages ? null : this.totalPages - this.clampedPages; } - // providerChanged: Ember.on('init', Ember.observer('provider', function() { - // // For PREPRINTS and REGISTRIES - watches provider query param for changes and modifies activeFilters - // let filter = this.get('provider'); - // if (!filter || filter === 'true' || typeof filter === 'object') return; - // if (!this.get('theme.isProvider')) { - // this.setActiveFiltersAndReload('activeFilters.providers', filter.split('OR')); - // } - // })) - - // reloadSearch: Ember.observer('activeFilters.providers.@each', - // 'activeFilters.subjects.@each', 'activeFilters.types.@each', function() { - // // For PREPRINTS and REGISTRIES. Reloads page if activeFilters change. - // this.set('page', 1); - // this.loadPage(); - // }), - @computed('currentUser.sessionKey') get searchUrl() { // Pulls SHARE search url from config file. return `${config.OSF.shareSearchUrl}?preference=${this.currentUser.sessionKey}`; } - // subjectChanged: Ember.on('init', Ember.observer('subject', function() { - // // For PREPRINTS - watches subject query param for changes and modifies activeFilters - // let filter = this.get('subject'); - // if (!filter || filter === 'true' || typeof filter === 'object') return; - // this.setActiveFiltersAndReload('activeFilters.subjects', filter.split('OR')); - // })), - // typeChanged: Ember.on('init', Ember.observer('type', function() { - // // For REGISTRIES - watches type query param for changes and modifies activeFilters - // let filter = this.get('type'); - // if (!filter || filter === 'true' || typeof filter === 'object') return; - // this.setActiveFiltersAndReload('activeFilters.types', filter.split('OR')); - // })), - // Total pages of search results @computed('numberOfResults', 'size') get totalPages(): number { @@ -765,9 +719,8 @@ export default class DiscoverPage extends Component.extend({ // Clear all of the activeFilters Object.values(this.facetContexts) .forEach(context => { - // context.activeFilter.clear(); setProperties(context, { - activeFilter: [], + activeFilter: [...context.lockedActiveFilter], queryParam: '', currentQueryFilters: context.defaultQueryFilters, }); diff --git a/lib/collections/addon/components/discover-page/facets/base/component.ts b/lib/collections/addon/components/discover-page/facets/base/component.ts index 0e6effd183c..7a31bfcc940 100644 --- a/lib/collections/addon/components/discover-page/facets/base/component.ts +++ b/lib/collections/addon/components/discover-page/facets/base/component.ts @@ -2,8 +2,8 @@ import { action } from '@ember-decorators/object'; import { service } from '@ember-decorators/service'; import Component from '@ember/component'; import { assert } from '@ember/debug'; -import Theme from 'collections/services/theme'; import Analytics from 'ember-osf-web/services/analytics'; +import Theme from 'ember-osf-web/services/theme'; import { FacetContext } from '../../component'; diff --git a/lib/collections/addon/components/discover-page/facets/checklist/component.ts b/lib/collections/addon/components/discover-page/facets/checklist/component.ts new file mode 100644 index 00000000000..b4cb8d8ff79 --- /dev/null +++ b/lib/collections/addon/components/discover-page/facets/checklist/component.ts @@ -0,0 +1,123 @@ +import { computed } from '@ember-decorators/object'; +import { service } from '@ember-decorators/service'; +import { setProperties } from '@ember/object'; +import { task } from 'ember-concurrency'; +import DS from 'ember-data'; +import Collection from 'ember-osf-web/models/collection'; +import CollectionProvider from 'ember-osf-web/models/collection-provider'; +import Base from '../base/component'; +import styles from './styles'; +import layout from './template'; + +interface Item { + key: string; +} + +/** + * Builds preprint provider facets for discover page. + * To be used with discover-page component and faceted-search component. + * + * Sample usage: + * ```handlebars + * {{search-facet-provider + * updateFilters=(action 'updateFilters') + * activeFilters=activeFilters + * options=facet + * filterReplace=filterReplace + * key=key + * }} + * ``` + * @class search-facet-provider + */ +export default abstract class SearchFacetChecklist extends Base.extend({ + didReceiveAttrs(this: SearchFacetChecklist, ...args: any[]) { + this._super(...args); + + const { context, filterChanged } = this; + + setProperties(context, { + updateFilters(item?: string) { + const { activeFilter, defaultQueryFilters } = context; + + if (item) { + const method = activeFilter.includes(item) ? 'removeObject' : 'pushObject'; + activeFilter[method](item); + } + + setProperties(context, { + queryParam: activeFilter.join('OR'), + currentQueryFilters: !activeFilter.length ? + defaultQueryFilters : + [ + { + terms: { + sources: activeFilter, + }, + }, + ], + }); + + filterChanged(); + }, + }); + + this.initialize.perform(); + }, + + initialize: task(function *(this: SearchFacetChecklist): IterableIterator { + const providers: CollectionProvider[] = this.theme.isProvider ? + [this.theme.provider] : + yield this.store.findAll('collection-provider', { + include: 'primary_collection', + }); + + const primaryCollections: Collection[] = yield Promise.all( + providers.map(({ primaryCollection }) => primaryCollection), + ); + + const allItems = primaryCollections + .reduce( + (acc, val) => [...acc, ...(val[this.attribute] as string[])], + [], + ) + .map(key => ({ key })); + + this.setProperties({ + allItems, + }); + + setProperties(this.context, { + didInit: true, + defaultQueryFilters: [ + // { + // terms: { + // // if there are no providers checked, use all whitelisted providers in the query + // sources: this.otherProviders.mapBy('key'), + // }, + // }, + ], + }); + + this.context.updateFilters(); + }), +}) { + layout = layout; + styles = styles; + + @service store!: DS.Store; + + allItems: Item[] = []; + + abstract attribute: keyof Collection; + + @computed('allItems', 'context.activeFilter.[]') + get items(this: SearchFacetChecklist) { + const { activeFilter } = this.context; + + return this.allItems + .map(item => ({ + ...item, + checked: activeFilter.includes(item.key), + })); + } +} diff --git a/lib/collections/addon/components/discover-page/facets/checklist/styles.scss b/lib/collections/addon/components/discover-page/facets/checklist/styles.scss new file mode 100644 index 00000000000..7f4e19e1249 --- /dev/null +++ b/lib/collections/addon/components/discover-page/facets/checklist/styles.scss @@ -0,0 +1,9 @@ +.nobullet { + list-style: none; + padding-left: 25px; +} + +.label { + font-weight: normal; + font-size: 14px; +} diff --git a/lib/collections/addon/components/discover-page/facets/checklist/template.hbs b/lib/collections/addon/components/discover-page/facets/checklist/template.hbs new file mode 100644 index 00000000000..0039f7656a9 --- /dev/null +++ b/lib/collections/addon/components/discover-page/facets/checklist/template.hbs @@ -0,0 +1,16 @@ +
+ +
diff --git a/lib/collections/addon/components/discover-page/facets/collected-type/component.ts b/lib/collections/addon/components/discover-page/facets/collected-type/component.ts new file mode 100644 index 00000000000..8116d78a67b --- /dev/null +++ b/lib/collections/addon/components/discover-page/facets/collected-type/component.ts @@ -0,0 +1,6 @@ +import Collection from 'ember-osf-web/models/collection'; +import Checklist from '../checklist/component'; + +export default class CollectedType extends Checklist { + attribute: keyof Collection = 'collectedTypeChoices'; +} diff --git a/lib/collections/addon/components/discover-page/facets/collection-provider/component.ts b/lib/collections/addon/components/discover-page/facets/collection-provider/component.ts new file mode 100644 index 00000000000..15f41c90fef --- /dev/null +++ b/lib/collections/addon/components/discover-page/facets/collection-provider/component.ts @@ -0,0 +1,148 @@ +import { computed } from '@ember-decorators/object'; +import { service } from '@ember-decorators/service'; +import { setProperties } from '@ember/object'; +import config from 'collections/config/environment'; +import { task } from 'ember-concurrency'; +import DS from 'ember-data'; +import Provider from 'ember-osf-web/models/provider'; +import Base from '../base/component'; +import styles from './styles'; +import layout from './template'; + +const { + OSF: { + url, + }, +} = config; + +interface ShareProviderHit { + key: string; + doc_count: number; // eslint-disable-line camelcase +} + +/** + * Builds preprint provider facets for discover page. + * To be used with discover-page component and faceted-search component. + * + * Sample usage: + * ```handlebars + * {{search-facet-provider + * updateFilters=(action 'updateFilters') + * activeFilters=activeFilters + * options=facet + * filterReplace=filterReplace + * key=key + * }} + * ``` + * @class search-facet-provider + */ +export default class SearchFacetProvider extends Base.extend({ + didReceiveAttrs(this: SearchFacetProvider, ...args: any[]) { + this._super(...args); + + const { context, filterChanged, theme } = this; + + setProperties(context, { + lockedActiveFilter: this.theme.isProvider ? [] : [], + updateFilters(item?: string) { + const { activeFilter, defaultQueryFilters } = context; + + if (item) { + const method = activeFilter.includes(item) ? 'removeObject' : 'pushObject'; + activeFilter[method](item); + } + + const queryParam = theme.isProvider ? '' : activeFilter.join('OR'); + + setProperties(context, { + queryParam, + currentQueryFilters: !activeFilter.length ? + defaultQueryFilters : + [ + { + terms: { + sources: activeFilter, + }, + }, + ], + }); + + filterChanged(); + }, + }); + + this.initialize.perform(); + }, + + initialize: task(function *(this: SearchFacetProvider): IterableIterator { + if (this.theme.isProvider) { + const key = this.theme.provider!.name; + + this.set('allProviders', [ + { + key, + doc_count: 0, + }, + ]); + + this.context.lockedActiveFilter.pushObject(key); + this.context.activeFilter.pushObject(key); + } else { + const providers: Provider[] = yield this.store.findAll('collection-provider'); + + this.set('allProviders', providers.map(({ name }) => ({ + key: name, + doc_count: 0, + }))); + } + + setProperties(this.context, { + didInit: true, + defaultQueryFilters: [ + // { + // terms: { + // // if there are no providers checked, use all whitelisted providers in the query + // sources: this.otherProviders.mapBy('key'), + // }, + // }, + ], + }); + + this.context.updateFilters(); + + this.filterChanged(); + }), +}) { + layout = layout; + styles = styles; + + @service store!: DS.Store; + + allProviders!: ShareProviderHit[]; + + @computed('allProviders.[]') + get checkedProviders() { + return this.allProviders.filterBy('checked', true); + } + + @computed('checkedProviders') + get activeProviders() { + return this.checkedProviders.mapBy('key'); + } + + @computed('osfUrl') + get otherReposLink(): string { + return `${url}collections/discover`; + } + + @computed('theme.provider', 'allProviders', 'context.activeFilter.[]') + get providers() { + const { activeFilter } = this.context; + + return this.allProviders + .map(provider => ({ + ...provider, + checked: activeFilter.includes(provider.key), + })); + } +} diff --git a/lib/collections/addon/components/discover-page/facets/provider/styles.scss b/lib/collections/addon/components/discover-page/facets/collection-provider/styles.scss similarity index 100% rename from lib/collections/addon/components/discover-page/facets/provider/styles.scss rename to lib/collections/addon/components/discover-page/facets/collection-provider/styles.scss diff --git a/lib/collections/addon/components/discover-page/facets/collection-provider/template.hbs b/lib/collections/addon/components/discover-page/facets/collection-provider/template.hbs new file mode 100644 index 00000000000..df85e5a1231 --- /dev/null +++ b/lib/collections/addon/components/discover-page/facets/collection-provider/template.hbs @@ -0,0 +1,26 @@ +
+
    + {{#each providers as |item|}} +
  • + +
  • + {{/each}} + {{#if theme.isProvider}} + + {{t 'collections.discover.other_repositories'}} + + {{/if}} +
+
diff --git a/lib/collections/addon/components/discover-page/facets/provider/component.ts b/lib/collections/addon/components/discover-page/facets/preprint-provider/component.ts similarity index 100% rename from lib/collections/addon/components/discover-page/facets/provider/component.ts rename to lib/collections/addon/components/discover-page/facets/preprint-provider/component.ts diff --git a/lib/collections/addon/components/discover-page/facets/preprint-provider/styles.scss b/lib/collections/addon/components/discover-page/facets/preprint-provider/styles.scss new file mode 100644 index 00000000000..e3fef0ec087 --- /dev/null +++ b/lib/collections/addon/components/discover-page/facets/preprint-provider/styles.scss @@ -0,0 +1,9 @@ +.nobullet { + list-style: none; + padding-left: 25px; +} + +.provider-label { + font-weight: normal; + font-size: 14px; +} diff --git a/lib/collections/addon/components/discover-page/facets/provider/template.hbs b/lib/collections/addon/components/discover-page/facets/preprint-provider/template.hbs similarity index 100% rename from lib/collections/addon/components/discover-page/facets/provider/template.hbs rename to lib/collections/addon/components/discover-page/facets/preprint-provider/template.hbs diff --git a/lib/collections/addon/components/discover-page/facets/status/component.ts b/lib/collections/addon/components/discover-page/facets/status/component.ts new file mode 100644 index 00000000000..88a5a003292 --- /dev/null +++ b/lib/collections/addon/components/discover-page/facets/status/component.ts @@ -0,0 +1,6 @@ +import Collection from 'ember-osf-web/models/collection'; +import Checklist from '../checklist/component'; + +export default class Status extends Checklist { + attribute: keyof Collection = 'statusChoices'; +} diff --git a/lib/collections/addon/components/discover-page/facets/taxonomy/component.ts b/lib/collections/addon/components/discover-page/facets/taxonomy/component.ts index b2027d7656a..37c374a545c 100644 --- a/lib/collections/addon/components/discover-page/facets/taxonomy/component.ts +++ b/lib/collections/addon/components/discover-page/facets/taxonomy/component.ts @@ -1,8 +1,8 @@ import { service } from '@ember-decorators/service'; import { setProperties } from '@ember/object'; -import Theme from 'collections/services/theme'; -import PreprintProvider from 'ember-osf-web/models/preprint-provider'; +import Provider from 'ember-osf-web/models/provider'; import Taxonomy from 'ember-osf-web/models/taxonomy'; +import Theme from 'ember-osf-web/services/theme'; import Base from '../base/component'; import styles from './styles'; import layout from './template'; @@ -91,7 +91,7 @@ export default class SearchFacetTaxonomy extends Base.extend({ SearchFacetTaxonomy.getTaxonomies(this.item, this.theme.provider!); }, }) { - static async getTaxonomies(item: TaxonomyItem, provider: PreprintProvider) { + static async getTaxonomies(item: TaxonomyItem, provider: Provider) { const results: Taxonomy[] = await provider.queryHasMany('taxonomies', { filter: { parents: item.id }, page: { size: pageSize }, diff --git a/lib/collections/addon/components/discover-page/facets/taxonomy/item/component.ts b/lib/collections/addon/components/discover-page/facets/taxonomy/item/component.ts index 6254f5971db..a186bdefc94 100644 --- a/lib/collections/addon/components/discover-page/facets/taxonomy/item/component.ts +++ b/lib/collections/addon/components/discover-page/facets/taxonomy/item/component.ts @@ -3,9 +3,9 @@ import { action, computed } from '@ember-decorators/object'; import { alias } from '@ember-decorators/object/computed'; import { service } from '@ember-decorators/service'; import Component from '@ember/component'; -import Theme from 'collections/services/theme'; import { localClassNames } from 'ember-osf-web/decorators/css-modules'; import Analytics from 'ember-osf-web/services/analytics'; +import Theme from 'ember-osf-web/services/theme'; import SearchFacetTaxonomy, { TaxonomyItem } from '../component'; import styles from './styles'; import layout from './template'; diff --git a/lib/collections/addon/components/discover-page/template.hbs b/lib/collections/addon/components/discover-page/template.hbs index a28c7f751ac..5758cce4407 100644 --- a/lib/collections/addon/components/discover-page/template.hbs +++ b/lib/collections/addon/components/discover-page/template.hbs @@ -8,6 +8,7 @@ {{#if (or theme.isProvider providerLogo)}}
+ {{provider-logo provider=theme.provider}}
{{/if}}
@@ -18,16 +19,18 @@

{{t discoverHeader documentType=themeProvider.documentType}}

{{/if}} {{!POWERED BY SHARE}} -

- {{t 'eosf.components.discoverPage.poweredBy'}} - -

+ {{#if isPoweredByShare}} +

+ {{t 'eosf.components.discoverPage.poweredBy'}} + +

+ {{/if}}
@@ -163,7 +166,7 @@ {{!RESULTS FOUND}}
{{#each results as |result|}} - {{search-result + {{!search-result themeProvider=themeProvider queryParams=queryParams detailRoute=detailRoute diff --git a/lib/collections/addon/components/error-page/component.ts b/lib/collections/addon/components/error-page/component.ts index 40092b9a8e7..8e7a1856ee4 100644 --- a/lib/collections/addon/components/error-page/component.ts +++ b/lib/collections/addon/components/error-page/component.ts @@ -1,9 +1,9 @@ import { computed } from '@ember-decorators/object'; import { service } from '@ember-decorators/service'; import Component from '@ember/component'; -import Theme from 'collections/services/theme'; -// import { localClassNames } from 'ember-osf-web/decorators/css-modules'; import Analytics from 'ember-osf-web/services/analytics'; +import Theme from 'ember-osf-web/services/theme'; +// import { localClassNames } from 'ember-osf-web/decorators/css-modules'; import defaultTo from 'ember-osf-web/utils/default-to'; // @localClassNames('header', 'header-error') diff --git a/lib/collections/addon/components/provider-logo/component.ts b/lib/collections/addon/components/provider-logo/component.ts new file mode 100644 index 00000000000..af3024b10ba --- /dev/null +++ b/lib/collections/addon/components/provider-logo/component.ts @@ -0,0 +1,31 @@ +import { tagName } from '@ember-decorators/component'; +import { computed } from '@ember-decorators/object'; +import { and } from '@ember-decorators/object/computed'; +import { service } from '@ember-decorators/service'; +import Component from '@ember/component'; +import Provider from 'ember-osf-web/models/provider'; +import Analytics from 'ember-osf-web/services/analytics'; +import styles from './styles'; +import layout from './template'; + +@tagName('') +export default class ProviderLogo extends Component { + layout = layout; + styles = styles; + + @service analytics!: Analytics; + + provider: Provider = this.provider; + + @and('provider.domain', 'provider.domainRedirectEnabled') + useExternalLink!: boolean; + + @computed('provider.id') + get logoAsset(): string { + return [ + '/ember_osf_web/assets/osf-assets/files/collections-assets/', + this.provider.id, + '/square_color_no_transparent.png', + ].join(''); + } +} diff --git a/lib/collections/addon/components/provider-logo/styles.scss b/lib/collections/addon/components/provider-logo/styles.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/collections/addon/components/provider-logo/template.hbs b/lib/collections/addon/components/provider-logo/template.hbs new file mode 100644 index 00000000000..55aed961858 --- /dev/null +++ b/lib/collections/addon/components/provider-logo/template.hbs @@ -0,0 +1,9 @@ +{{#if useExternalLink}} + + + +{{else}} + {{#link-to 'provider.discover' provider.id}} + + {{/link-to}} +{{/if}} diff --git a/lib/collections/addon/discover/controller.ts b/lib/collections/addon/discover/controller.ts index 0867d7d874b..899b613498d 100644 --- a/lib/collections/addon/discover/controller.ts +++ b/lib/collections/addon/discover/controller.ts @@ -3,8 +3,8 @@ import { not } from '@ember-decorators/object/computed'; import { service } from '@ember-decorators/service'; import Controller from '@ember/controller'; import config from 'collections/config/environment'; -import Theme from 'collections/services/theme'; import I18N from 'ember-i18n/services/i18n'; +import Theme from 'ember-osf-web/services/theme'; export default class Discover extends Controller { @service theme!: Theme; @@ -24,22 +24,23 @@ export default class Discover extends Controller { @not('additionalProviders') showActiveFilters!: boolean; - @computed('themeProvider') + @computed('theme.provider') get additionalProviders() { // Do additionalProviders exist? // for now, using this property to alter many pieces of the landing/discover page - return (this.themeProvider!.additionalProviders || []).length > 1; + // return (this.theme.provider!.additionalProviders || []).length > 1; + return false; } consumingService = 'collections'; // Consuming service - preprints here detailRoute = 'content'; // Name of detail route for this application - @computed('additionalProviders') - get discoverHeader(): string { // Header for preprints discover page - // If additionalProviders, use more generic Repository Search page title - return this.additionalProviders ? - 'discover.search.heading_repository_search' : - 'collections.discover.search_heading'; - } + // @computed('additionalProviders') + // get discoverHeader(): string { // Header for preprints discover page + // // If additionalProviders, use more generic Repository Search page title + // return this.additionalProviders ? + // 'discover.search.heading_repository_search' : + // 'collections.discover.search_heading'; + // } end = ''; // End query param. Must be passed to component, so can be reflected in the URL @@ -61,8 +62,10 @@ export default class Discover extends Controller { ] : // Regular preprints and branded preprints get provider and taxonomy facets [ - ['sources', 'providers', 'provider'], + ['sources', 'providers', 'collection-provider'], ['subjects', 'subject', 'taxonomy'], + ['status', 'status', 'status'], + ['type', 'type', 'collected-type'], ] ).map(([key, title, component]) => ({ key, diff --git a/lib/collections/addon/engine.js b/lib/collections/addon/engine.js index e25df414120..40c8b18eb7c 100644 --- a/lib/collections/addon/engine.js +++ b/lib/collections/addon/engine.js @@ -16,6 +16,7 @@ const engine = Engine.extend({ 'i18n', 'session', 'store', + 'theme', 'router', ], }, diff --git a/lib/collections/addon/index/controller.ts b/lib/collections/addon/index/controller.ts index 8970c8e73be..2a7fb158f60 100644 --- a/lib/collections/addon/index/controller.ts +++ b/lib/collections/addon/index/controller.ts @@ -1,9 +1,11 @@ import { service } from '@ember-decorators/service'; import Controller from '@ember/controller'; -import Theme from 'collections/services/theme'; +import Analytics from 'ember-osf-web/services/analytics'; +import Theme from 'ember-osf-web/services/theme'; import sanitizeHtml from 'sanitize-html'; export default class Index extends Controller { + @service analytics!: Analytics; @service theme!: Theme; sanitizeOptions = { diff --git a/lib/collections/addon/index/route.ts b/lib/collections/addon/index/route.ts index 7d17f096e5e..739f80cb9d3 100644 --- a/lib/collections/addon/index/route.ts +++ b/lib/collections/addon/index/route.ts @@ -1,7 +1,11 @@ +import { service } from '@ember-decorators/service'; import Route from '@ember/routing/route'; +import DS from 'ember-data'; export default class Index extends Route { - model(params: { provider_id: string }): string { - return params.provider_id; + @service store!: DS.Store; + + model() { + return this.store.findAll('collection-provider'); } } diff --git a/lib/collections/addon/index/styles.scss b/lib/collections/addon/index/styles.scss index becbd72ae5b..b999b64ab38 100644 --- a/lib/collections/addon/index/styles.scss +++ b/lib/collections/addon/index/styles.scss @@ -25,6 +25,18 @@ } } +.provider-logos { + background: url('img/index-tool-bg.jpg') top center #cbd9d5; + color: #fff; + text-shadow: 0 0 5px #506069; + background-size: cover; +} + +.source-code-link { + color: #fff; + text-decoration: underline; +} + .osf-bg { height: 70px; background-size: contain; diff --git a/lib/collections/addon/index/template.hbs b/lib/collections/addon/index/template.hbs index c774adc59f4..2c87a2aa68f 100644 --- a/lib/collections/addon/index/template.hbs +++ b/lib/collections/addon/index/template.hbs @@ -63,11 +63,63 @@
+ {{#unless theme.isProvider}} +
+
+
+
+

{{t 'collections.index.services_heading'}}

+

{{t 'collections.index.services_paragraph'}}

+
+
+
+ {{#each model as |provider|}} + {{provider-logo provider=provider}} + {{/each}} +
+
+
+

+ {{t 'collections.index.service_bottom.p1'}} +

+ {{t 'collections.index.service_bottom.div.line1'}} + + {{t 'collections.index.service_bottom.div.linkText1'}} + + {{t 'collections.index.service_bottom.div.line2'}} + + {{t 'collections.index.service_bottom.div.linkText2'}} + + {{t 'collections.index.service_bottom.div.line3'}} +
+

+ + {{t 'collections.index.service_bottom.contact'}} + +
+
+
+
+ {{/unless}} +
-

{{#if theme.provider.additionalProviders}} +

+ {{#if theme.provider.additionalProviders}} {{t "index.subjects.heading.provider"}} {{else}} {{!if theme.provider.hasHighlightedSubjects @@ -103,3 +155,5 @@

{{/if}}
+ +{{!-- --}} diff --git a/lib/collections/addon/provider/route.ts b/lib/collections/addon/provider/route.ts index 11208cd06c4..5c9ec48457b 100644 --- a/lib/collections/addon/provider/route.ts +++ b/lib/collections/addon/provider/route.ts @@ -1,8 +1,8 @@ import { service } from '@ember-decorators/service'; import Route from '@ember/routing/route'; import config from 'collections/config/environment'; -import Theme from 'collections/services/theme'; import DS from 'ember-data'; +import Theme from 'ember-osf-web/services/theme'; export default class Provider extends Route { @service store!: DS.Store; @@ -13,12 +13,12 @@ export default class Provider extends Route { const slugLower = slug.toLowerCase(); try { - await this.store.findRecord('preprint-provider', slugLower); - - const { pathname } = window.location; - const pathRegex = new RegExp(`^/collections/${slug}`); + await this.store.findRecord('collection-provider', slugLower); if (slug !== slugLower) { + const { pathname } = window.location; + const pathRegex = new RegExp(`^/collections/${slug}`); + window.location.pathname = pathname.replace( pathRegex, `/collections/${slugLower}`, diff --git a/lib/collections/package.json b/lib/collections/package.json index 5d67bcad4c5..de1581f73e3 100644 --- a/lib/collections/package.json +++ b/lib/collections/package.json @@ -21,6 +21,7 @@ }, "ember-addon": { "paths": [ + "../app-components", "../osf-components" ] } diff --git a/lib/osf-components/addon/components/branded-navbar/component.ts b/lib/osf-components/addon/components/branded-navbar/component.ts new file mode 100644 index 00000000000..73008609bd3 --- /dev/null +++ b/lib/osf-components/addon/components/branded-navbar/component.ts @@ -0,0 +1,16 @@ +import { service } from '@ember-decorators/service'; +import Component from '@ember/component'; +import Analytics from 'ember-osf-web/services/analytics'; +import styles from './styles'; +import layout from './template'; + +type ObjectType = 'collection' | 'preprint' | 'registration'; + +export default class BrandedNavbar extends Component { + layout = layout; + styles = styles; + + @service analytics!: Analytics; + + objectType: ObjectType = this.objectType; +} diff --git a/lib/osf-components/addon/components/branded-navbar/styles.scss b/lib/osf-components/addon/components/branded-navbar/styles.scss new file mode 100644 index 00000000000..e69de29bb2d diff --git a/lib/osf-components/addon/components/branded-navbar/template.hbs b/lib/osf-components/addon/components/branded-navbar/template.hbs new file mode 100644 index 00000000000..e472d3a9b5d --- /dev/null +++ b/lib/osf-components/addon/components/branded-navbar/template.hbs @@ -0,0 +1,27 @@ + \ No newline at end of file diff --git a/lib/osf-components/addon/components/osf-navbar/home-links/component.ts b/lib/osf-components/addon/components/osf-navbar/home-links/component.ts index efeeab837b1..e0fc0dc7eb5 100644 --- a/lib/osf-components/addon/components/osf-navbar/home-links/component.ts +++ b/lib/osf-components/addon/components/osf-navbar/home-links/component.ts @@ -1,4 +1,5 @@ import { tagName } from '@ember-decorators/component'; +import { computed } from '@ember-decorators/object'; import { equal } from '@ember-decorators/object/computed'; import { service } from '@ember-decorators/service'; import Component from '@ember/component'; @@ -9,6 +10,12 @@ import defaultTo from 'ember-osf-web/utils/default-to'; import Session from 'ember-simple-auth/services/session'; import layout from './template'; +const discoverPageApps = [ + 'collections', + 'registries', + 'preprints', +]; + /** * Display default OSF navbar links * @@ -29,5 +36,15 @@ export default class OsfNavbarHomeLinks extends Component { myProjectsUrl = serviceLinks.myProjects; reviewsUrl = serviceLinks.reviewsHome; + hostAppName: string = defaultTo(this.hostAppName, ''); + + @computed('router.currentRouteName') + get searchRoute(): string { + const { currentRouteName } = this.router; + const app = discoverPageApps.find(str => currentRouteName.startsWith(str)); + + return app ? `${app}.discover` : ''; + } + @equal('router.currentRouteName', 'institutions') onInstitutions!: boolean; } diff --git a/lib/osf-components/addon/components/osf-navbar/home-links/template.hbs b/lib/osf-components/addon/components/osf-navbar/home-links/template.hbs index 42ca0cd5dab..7fa369510f3 100644 --- a/lib/osf-components/addon/components/osf-navbar/home-links/template.hbs +++ b/lib/osf-components/addon/components/osf-navbar/home-links/template.hbs @@ -13,9 +13,15 @@ {{/if}}
  • - - {{t 'navbar.search'}} - + {{#if searchRoute}} + {{#link-to searchRoute}} + {{t 'navbar.search'}} + {{/link-to}} + {{else}} + + {{t 'navbar.search'}} + + {{/if}}
  • {{#if onInstitutions}}