Allow filtering events with multiple types (#519)

This commit is contained in:
Salvador de la Puente González 2020-04-15 11:37:30 +02:00 committed by GitHub
parent a7a3c31a5c
commit 7d1c836e1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 226 additions and 116 deletions

View File

@ -33,7 +33,7 @@
- Randomized Benchmarking
- Measuring Quantum Volume
### Chapter 6. Investigating Quantum Hardware Using Microwave Pulses
- Calibrating Qubits with OpenPulse
- Calibrating Qubits with Qiskit Pulse
- Accessing Higher Energy States
### Chapter 7. Demos
- Estimating Pi Using Quantum Phase Estimation Algorithm
### Chapter 7. Problem Sets & Exercises
### Chapter 8. Games & Demos

View File

@ -1,75 +1,85 @@
[
{
"title": "Hackathon @ Harvard",
"type": "Hackathon",
"image": "/images/events/promo-finland-unconference.jpg",
"types": [
"Hackathon",
"Camp"
],
"image": "/images/events/no-picture.jpg",
"place": "Boston, MA",
"location": "America",
"location": "Americas",
"date": "April 2-3, 2020"
},
{
"title": "Yale YQI Roundtable event",
"type": "Conference",
"image": "/images/events/promo-asia.jpg",
"types": [
"Conference",
"Hackathon"
],
"image": "/images/events/no-picture.jpg",
"place": "New Haven, CT",
"location": "Asia",
"date": "April 2, 2020",
"to": "/events/asia"
"location": "Asia Pacific",
"date": "April 2, 2020"
},
{
"title": "CQE Recruiting Forum",
"type": "Conference",
"image": "/images/events/promo-asia.jpg",
"types": [
"Conference"
],
"image": "/images/events/no-picture.jpg",
"place": "Chicago, IL",
"location": "Africa",
"location": "Online",
"date": "April 1, 2020"
},
{
"title": "Hackathon @ Uni College Dublin",
"type": "Hackathon",
"image": "/images/events/promo-finland-unconference.jpg",
"types": [
"Hackathon"
],
"image": "/images/events/no-picture.jpg",
"place": "Dublin, Ireland",
"location": "Asia Pacific",
"location": "Online",
"date": "March 28, 2020"
},
{
"title": "Q Meetup in Bangkok",
"type": "Conference",
"image": "/images/events/promo-finland-unconference.jpg",
"types": [
"Conference"
],
"image": "/images/events/no-picture.jpg",
"place": "Bangkok, Thailand",
"location": "Europe",
"location": "Asia Pacific",
"date": "March 26-31, 2020"
},
{
"title": "NSBE Annual Convention",
"type": "Conference",
"image": "/images/events/promo-vermont.jpg",
"types": [
"Conference"
],
"image": "/images/events/no-picture.jpg",
"place": "San Antonio, TX",
"location": "Africa",
"location": "Americas",
"date": "March 25-29, 2020",
"to": "http://convention.nsbe.org"
},
{
"title": "Hack-Q-Thon (NYC High School Hackathon)",
"type": "Hackathon",
"image": "/images/events/promo-finland-unconference.jpg",
"types": [
"Hackathon"
],
"image": "/images/events/no-picture.jpg",
"place": "NYU Campus, NY",
"location": "Europe",
"location": "Asia Pacific",
"date": "March 21, 2020"
},
{
"title": "Hackathon @ Uni College London",
"type": "Hackathon",
"image": "/images/events/promo-vermont.jpg",
"types": [
"Hackathon"
],
"image": "/images/events/no-picture.jpg",
"place": "London, England",
"location": "Africa",
"location": "Online",
"date": "March 19-20, 2020"
},
{
"title": "Qiskit Camp 2020 (NY)",
"type": "Camp",
"image": "/images/events/promo-finland-unconference.jpg",
"location": "Europe",
"date": "March 10-13, 2020"
}
]

View File

@ -1,16 +1,20 @@
[
{
"title": "Hackathon @ Princeton",
"type": "Hackathon",
"image": "/images/events/promo-vermont.jpg",
"types": [
"Hackathon"
],
"image": "/images/events/no-picture.jpg",
"place": "Princeton, NJ",
"location": "Africa",
"location": "Europe",
"date": "April 18-19, 2020"
},
{
"title": "Hackathon @ Stanford",
"type": "Hackathon",
"image": "/images/events/promo-finland-unconference.jpg",
"types": [
"Hackathon"
],
"image": "/images/events/no-picture.jpg",
"place": "Stanford, CA",
"location": "Online",
"date": "May 1-2, 2020"

View File

@ -5,7 +5,8 @@ import {
CommunityEvent,
CommunityEventType,
WorldLocation,
LOCATION_CATEGORIES
LOCATION_CATEGORIES,
TYPE_CATEGORIES
} from '../store/modules/events'
const RECORD_FIELDS = {
@ -42,7 +43,7 @@ async function fetchCommunityEvents (apiKey: string, { days }): Promise<Communit
function convertToCommunityEvent (record: any): CommunityEvent {
return {
title: getName(record),
type: getType(record),
types: getTypes(record),
image: getImage(record),
place: getPlace(record),
location: getLocation(record),
@ -55,17 +56,16 @@ function getName (record: any): string {
return record.get(RECORD_FIELDS.name)
}
function getType (record: any): CommunityEventType {
if (record.get(RECORD_FIELDS.name).toLowerCase().includes('qiskit camp')) {
return 'Camp'
}
if ((record.get(RECORD_FIELDS.typeOfEvent) || []).includes('Hackathon')) {
return 'Hackathon'
}
if ((record.get(RECORD_FIELDS.typeOfEvent) || []).includes('Unconference')) {
return 'Unconference'
}
return 'Conference'
function getTypes (record: any): CommunityEventType[] {
const value = record.get(RECORD_FIELDS.typeOfEvent) || []
const valueList = (Array.isArray(value) ? value : [value]) as string[]
const communityEventTypes = filterWithWhitelist(valueList, TYPE_CATEGORIES)
const noTypes = communityEventTypes.length === 0
return noTypes ? ['Conference'] : communityEventTypes
}
function filterWithWhitelist<W> (list: any[], whitelist: W[]): W[] {
return list.filter((type): type is W => whitelist.includes(type))
}
function getImage (record: any): string {
@ -151,11 +151,12 @@ export {
fetchCommunityEvents,
convertToCommunityEvent,
getName,
getType,
getTypes,
getImage,
getPlace,
getLocation,
getWebsite,
getDates,
formatDates
formatDates,
filterWithWhitelist
}

View File

@ -2,6 +2,7 @@
// https://github.com/Al-un/learn-nuxt-ts/blob/master/docs/06.test.md
module.exports = {
preset: 'ts-jest/presets/js-with-ts',
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1'

View File

@ -67,7 +67,7 @@
<EventCard
v-for="event in filteredEvents"
:key="`${event.place}-${event.date}`"
:type="event.type"
:type="formatType(event.types)"
:title="event.title"
:image="event.image"
:place="event.place"
@ -187,6 +187,10 @@ export default class extends QiskitPage {
this.$store.commit('setActiveSet', activeSet)
}
formatType (types: CommunityEvent[]): string {
return types.join(', ')
}
}
</script>

View File

@ -3,7 +3,7 @@ type WorldLocation = 'Americas'|'Asia Pacific'|'Europe'|'Africa'|'TBD'|'Online'
type CommunityEventType = 'Hackathon'|'Camp'|'Unconference'|'Conference'
type CommunityEvent = {
type: CommunityEventType,
types: CommunityEventType[],
title: string,
image: string,
place: string,
@ -13,16 +13,25 @@ type CommunityEvent = {
}
const LOCATION_CATEGORIES: WorldLocation[] = ['Americas', 'Asia Pacific', 'Europe', 'Africa', 'Online']
const TYPE_CATEGORIES: CommunityEventType[] = ['Hackathon', 'Camp', 'Unconference']
export { CommunityEvent, CommunityEventType, WorldLocation, LOCATION_CATEGORIES }
export {
CommunityEvent,
CommunityEventType,
WorldLocation,
LOCATION_CATEGORIES,
TYPE_CATEGORIES
}
export default {
state: {
activeSet: 'upcoming',
upcomingCommunityEvents: [],
pastCommunityEvents: [],
typeFilters: [],
locationFilters: []
state () {
return {
activeSet: 'upcoming',
upcomingCommunityEvents: [],
pastCommunityEvents: [],
typeFilters: [],
locationFilters: []
}
},
getters: {
typeFilters (state) {
@ -46,16 +55,20 @@ export default {
if (noTypeFilters && noLocationFilters) { return events }
const eventsAfterApplyTypeFilter = filterBy(events, typeFilters, 'type')
const eventsAfterApplyTypeFilter = filterBy(events, typeFilters, 'types')
return filterBy(eventsAfterApplyTypeFilter, locationFilters, 'location')
function filterBy (allEvents, selectedFilters, propToFilter) {
function filterBy (allEvents: CommunityEvent[], selectedFilters: string[], propToFilter: keyof CommunityEvent) {
const noFilters = selectedFilters.length === 0
if (noFilters) { return allEvents }
return allEvents.filter(event => selectedFilters.includes(event[propToFilter]))
return allEvents.filter((event) => {
const propValue = event[propToFilter]
const valueArray = Array.isArray(propValue) ? propValue : [propValue]
return valueArray.some(value => selectedFilters.includes(value))
})
}
}
},

View File

@ -1,8 +1,9 @@
import {
RECORD_FIELDS,
formatDates,
filterWithWhitelist,
convertToCommunityEvent,
getType,
getTypes,
getDates,
getImage
} from '~/hooks/event-conversion-utils'
@ -10,7 +11,7 @@ import {
type RecordFields = {
name: string,
picture?: object[],
types?: string[],
types?: string[]|string,
location?: string,
startDate?: string,
endDate?: string,
@ -47,12 +48,12 @@ describe('convertToCommunityEvent', () => {
website: 'https://qiskit.org/events'
})
it('extract and format information from the record', () => {
it('extracts and format information from the record', () => {
// TODO: Now ignoring image and location since they are random. Add them once implemented.
const { title, type, place, date, to } = convertToCommunityEvent(fakeRecord)
expect({ title, type, place, date, to }).toEqual({
const { title, types, place, date, to } = convertToCommunityEvent(fakeRecord)
expect({ title, types, place, date, to }).toEqual({
title: 'Fake conference',
type: 'Hackathon',
types: ['Hackathon'],
place: 'Someplace',
date: 'January 1-2, 2020',
to: 'https://qiskit.org/events'
@ -61,59 +62,42 @@ describe('convertToCommunityEvent', () => {
})
describe('getType', () => {
it('checks the name contains the "qiskit camp" pattern regardless the capitalization', () => {
it('filters the values so only those in the whitelist gets into the event', () => {
const camp = new FakeRecord({
name: 'qisKit CamP Oceania',
types: ['Hackathon', 'Community']
name: 'Fake Camp',
types: ['Hackathon', 'Community', 'Unknown']
})
expect(getType(camp)).toBe('Camp')
expect(getTypes(camp)).toEqual(['Hackathon'])
})
it('defaults in "Conference" if there is no type', () => {
it('gets the default type if there is no type', () => {
const camp = new FakeRecord({
name: 'Fake Conference'
name: 'Fake Camp'
})
expect(getType(camp)).toBe('Conference')
expect(getTypes(camp)).toEqual(['Conference'])
})
it('defaults in "Conference" if cannot infer the type', () => {
it('gets the default type if no type is in the whitelist', () => {
const camp = new FakeRecord({
name: 'Fake Camp',
types: ['A', 'B', 'C']
})
expect(getTypes(camp)).toEqual(['Conference'])
})
it('gets an array of one value if the type is not an array but one value', () => {
const camp = new FakeRecord({
name: 'Fake Conference',
types: ['xxxx', 'yyyy']
types: 'Hackathon'
})
expect(getType(camp)).toBe('Conference')
expect(getTypes(camp)).toEqual(['Hackathon'])
})
})
it('infers "Hackathon" if "Hackathon" is among the tags', () => {
const camp = new FakeRecord({
name: 'Fake Conference',
types: ['Hackathon', 'Education']
})
expect(getType(camp)).toBe('Hackathon')
})
it('infers "Unconference" if "Unconference" is among the types', () => {
const event = new FakeRecord({
name: 'Fake Conference',
types: ['Unconference', 'Education']
})
expect(getType(event)).toBe('Unconference')
})
it('gives "Hackathon" preference over "Unconference"', () => {
const event = new FakeRecord({
name: 'Fake Conference',
types: ['Hackathon', 'Unconference']
})
expect(getType(event)).toBe('Hackathon')
})
it('gives "Camp" preference over "Hackathon"', () => {
const event = new FakeRecord({
name: 'Qiskit Camp Oceania',
types: ['Hackathon', 'Unconference']
})
expect(getType(event)).toBe('Camp')
describe('filterByWhitelist', () => {
it('creates a new list, from an input one, only with the values in a whitelist', () => {
const list = ['a', 'x', 'b', 'y', 'c', 'z', 'a', 'x', 'b', 'y']
expect(filterWithWhitelist(list, ['a', 'b', 'c'])).toEqual(['a', 'b', 'c', 'a', 'b'])
})
})
@ -236,11 +220,11 @@ describe('formatDates', () => {
expect(formatDates(start, endNextYear)).toBe('January 1, 2020 - January 1, 2021')
})
it('factor out the year when years are equal', () => {
it('factors out the year when years are equal', () => {
expect(formatDates(start, endNextMonth)).toBe('January 1 - February 1, 2020')
})
it('factour out year and month when the event falls into the same month', () => {
it('factors out year and month when the event falls into the same month', () => {
expect(formatDates(start, endNextDay)).toBe('January 1-2, 2020')
})
})

View File

@ -0,0 +1,93 @@
import createStore from '~/store'
describe('module events', () => {
let store: any
const unconferenceCampInAsia = {
title: 'Fake event A',
types: ['Unconference', 'Camp'],
location: 'Asia Pacific'
}
const hackathonInEurope = {
title: 'Fake event B',
types: ['Unconference', 'Hackathon'],
location: 'Europe'
}
const campInAfrica = {
title: 'Fake event C',
types: ['Camp'],
location: 'Africa'
}
const hackathonInAmericas = {
title: 'Fake event D',
types: ['Camp', 'Hackathon'],
location: 'Americas'
}
const unconferenceOnline = {
title: 'Fake event E',
types: ['Unconference'],
location: 'Online'
}
const futureEvents = [unconferenceCampInAsia, hackathonInEurope, campInAfrica]
const pastEvents = [hackathonInAmericas, unconferenceOnline]
beforeEach(() => {
store = createStore()
store.commit('setEvents', {
events: 'upcomingCommunityEvents',
eventsSet: futureEvents
})
store.commit('setEvents', {
events: 'pastCommunityEvents',
eventsSet: pastEvents
})
})
describe('filteredEvents', () => {
it('gets future events by default', () => {
expect(store.getters.filteredEvents).toEqual(futureEvents)
})
it('gets past events after setting the the active set to past', () => {
store.commit('setActiveSet', 'past')
expect(store.getters.filteredEvents).toEqual(pastEvents)
})
it('gets active-set filtered by location', () => {
store.commit('addFilter', {
filter: 'locationFilters',
filterValue: 'Asia Pacific'
})
expect(store.getters.filteredEvents).toEqual([unconferenceCampInAsia])
})
it('gets active-set filtered by type', () => {
store.commit('addFilter', {
filter: 'typeFilters',
filterValue: 'Hackathon'
})
expect(store.getters.filteredEvents).toEqual([hackathonInEurope])
})
it('gets active-set filtered by type, considering events with several types', () => {
store.commit('addFilter', {
filter: 'typeFilters',
filterValue: 'Camp'
})
expect(store.getters.filteredEvents).toEqual([unconferenceCampInAsia, campInAfrica])
})
it('gets active-set filtered by type and location', () => {
store.commit('addFilter', {
filter: 'typeFilters',
filterValue: 'Camp'
})
store.commit('addFilter', {
filter: 'locationFilters',
filterValue: 'Africa'
})
expect(store.getters.filteredEvents).toEqual([campInAfrica])
})
})
})