Skip to content

Commit 1c28994

Browse files
committed
Fetch data from the CCOS repo, hydrate the app and mount
1 parent 93673ed commit 1c28994

File tree

1 file changed

+23
-264
lines changed

1 file changed

+23
-264
lines changed

webpack/js/issue-finder.js

+23-264
Original file line numberDiff line numberDiff line change
@@ -1,269 +1,28 @@
1-
import {Octokit} from '@octokit/rest';
21
import Vue from 'vue';
32

4-
import VueSelect from 'vue-select';
3+
import {hydrateAppWithData} from './hydration';
4+
import {App} from './components'
55

6-
const octokit = new Octokit({
7-
auth: ''
8-
});
9-
10-
const IssueCard = {
11-
template: `
12-
<div class="card entry-post vertical margin-top-normal padding-normal">
13-
<h4 class="card-title b-header margin-bottom-small">{{ issue.title }}</h4>
14-
<a :href="issue.html_url" class="button is-text tiny site-link" target="_blank">
15-
<span class="has-color-forest-green">
16-
{{ issue.repository.name }}#{{ issue.number }}
17-
</span>
18-
<i class="icon external-link has-color-forest-green"></i>
19-
</a>
20-
<div class="labels margin-top-small">
21-
<span
22-
v-for="labelName in issue.labelNames"
23-
class="button tag margin-right-small">
24-
{{ labelName }}
25-
</span>
26-
</div>
27-
</div>`,
28-
props: {
29-
issue: {
30-
type: Object,
31-
required: true
32-
},
33-
}
34-
}
35-
36-
const App = {
37-
el: '#vue-app',
38-
template: `
39-
<div class="find-issues">
40-
<form id="filters">
41-
<label for="aspect">
42-
<strong>Aspect</strong><br>
43-
What aspect of the codebase would you like to work on?
44-
Leave blank if you don't have a preference.
45-
</label>
46-
<VueSelect
47-
v-model="filters.aspect"
48-
id="aspect"
49-
name="aspect"
50-
:options="options.aspects"
51-
label="name"
52-
:reduce="aspect => aspect.code"/>
53-
54-
<label for="skills">
55-
<strong>Skill set</strong><br>
56-
Choose up to three skills that you would like to see issues for.
57-
Leave blank if you don't have a preference.
58-
</label>
59-
<VueSelect
60-
v-model="filters.skills"
61-
id="skills"
62-
name="skills"
63-
:options="options.skills"
64-
label="name"
65-
:reduce="skill => skill.code"
66-
:selectable="() => filters.skills.length < 3"
67-
multiple/>
68-
69-
<label for="experience">
70-
<strong>Experience</strong><br>
71-
Are you a new contributor or do you have experience working with CC?
72-
</label>
73-
<VueSelect
74-
v-model="filters.experience"
75-
id="experience"
76-
name="experience"
77-
:options="options.experiences"
78-
label="name"
79-
:reduce="experience => experience.code"
80-
:clearable="false"/>
6+
$(document).ready(function () {
7+
const BASE_URL = 'https://raw.githubusercontent.com/creativecommons/ccos-scripts/master/normalize_repos'
8+
const FILE_URL = name => `${BASE_URL}/${name}.json`
819

82-
<button
83-
class="button small is-success margin-top-small"
84-
@click.prevent="search">
85-
Search
86-
</button>
87-
</form>
88-
89-
<template v-if="issues.length">
90-
<issue-card
91-
v-for="issue in filteredIssues"
92-
:key="issue.id"
93-
:issue="issue"/>
94-
</template>
95-
<p
96-
v-else
97-
class="margin-top-normal">
98-
No results.
99-
</p>
100-
</div>`,
101-
components: {
102-
VueSelect,
103-
IssueCard
104-
},
105-
data() {
106-
return {
107-
message: 'Hello',
108-
options: {
109-
skills: [
110-
{
111-
name: 'Python',
112-
code: 'python'
113-
},
114-
{
115-
name: 'JavaScript',
116-
code: 'javascript'
117-
},
118-
{
119-
name: 'Sass',
120-
code: 'sass'
121-
}
122-
],
123-
experiences: [
124-
{
125-
name: 'New contributor',
126-
code: 'beginner'
127-
},
128-
{
129-
name: 'Experienced',
130-
code: 'experienced'
131-
}
132-
],
133-
aspects: [
134-
{
135-
name: '📄 Text',
136-
code: '📄 aspect: text'
137-
},
138-
{
139-
name: '💻 Code',
140-
code: '💻 aspect: code'
141-
},
142-
{
143-
name: '🕹 Interface',
144-
code: '🕹 aspect: interface'
145-
},
146-
{
147-
name: '🤖 DX',
148-
code: '🤖 aspect: dx'
149-
}
150-
]
151-
},
152-
filters: {
153-
aspect: null,
154-
skills: [],
155-
experience: 'experienced'
156-
},
157-
issues: []
158-
}
159-
},
160-
computed: {
161-
/**
162-
* Get a nested list of all the labels to search for. This is a combination
163-
* of the experience and aspect filter only. The skills filter must be
164-
* applied on the client side due to limitations of the GitHub API.
165-
*
166-
* This returns a list of lists. Each nested list corresponds to a single
167-
* API query and multiple queries need to be run to get the combined set of
168-
* valid issues.
169-
*
170-
* @returns {array} - the array of array of labels
171-
*/
172-
labelsList() {
173-
const labelsList = [
174-
['good first issue']
175-
]
176-
if (this.filters.experience === 'experienced') {
177-
labelsList.push(['help wanted'])
178-
}
179-
if (this.filters.aspect) {
180-
labelsList.forEach(labels => {
181-
labels.push(this.filters.aspect)
182-
})
183-
}
184-
return labelsList
185-
},
186-
/**
187-
* Get all the promises which will yield the issues being searched for.
188-
*
189-
* @returns {array} - the array of promises that will resolve to issues
190-
*/
191-
promises() {
192-
return this.labelsList.map(labels => this.promise(labels))
193-
},
194-
/**
195-
* Remove duplicates from the list of issues. Since two different API
196-
* queries are being collated, some issues may appear more than once. This
197-
* action removes such duplicates from the union of both results.
198-
*
199-
* @returns {array} - the array of issues without any duplicate entries
200-
*/
201-
dedupedIssues() {
202-
const ids = new Set()
203-
const deduped = []
204-
this.issues.forEach(issue => {
205-
if (ids.has(issue.id)) {
206-
return
207-
}
208-
deduped.push(issue)
209-
ids.add(issue.id)
210-
})
211-
return deduped
212-
},
213-
filteredIssues() {
214-
let filtered = this.dedupedIssues
215-
if (this.filters.skills.length) {
216-
filtered = filtered.filter(issue => {
217-
const joinedLabels = issue.labelNames.join(',')
218-
return this.filters.skills.some(skill => joinedLabels.includes(skill))
219-
})
220-
}
221-
return filtered
222-
}
223-
},
224-
methods: {
225-
/**
226-
* Get a Promise for the list of issues pertaining to a given skill.
227-
*
228-
* @param {Array} labels - list of labels to search for
229-
* @returns {Promise} a promise that resolves into a list of issues
230-
*/
231-
promise(labels = []) {
232-
const params = {
233-
org: 'creativecommons',
234-
state: 'open',
235-
filter: 'all'
236-
}
237-
if (labels) {
238-
params.labels = labels.join(',')
239-
}
240-
return octokit
241-
.issues
242-
.listForOrg(params)
243-
.then(response => response.data)
244-
},
245-
/**
246-
* Run the search based on the data submitted via the form and load all
247-
* results into the `issues` attribute.
248-
*/
249-
search() {
250-
Promise
251-
.all(this.promises)
252-
.then(issueLists => {
253-
const issues = issueLists.flat()
254-
issues.forEach(issue => {
255-
issue.labelNames = issue.labels.map(label => label.name)
10+
Promise
11+
.all([
12+
fetch(FILE_URL('skills'))
13+
.then(response => response.json())
14+
.then(data => {
15+
window.skills = data
16+
}),
17+
fetch(FILE_URL('labels'))
18+
.then(response => response.json())
19+
.then(data => {
20+
window.labels = data
25621
})
257-
this.issues = issues
258-
})
259-
.catch(err => console.error(err))
260-
}
261-
},
262-
mounted() {
263-
this.search()
264-
}
265-
}
266-
267-
$(document).ready(function () {
268-
window.app = new Vue(App)
269-
})
22+
])
23+
.then(() => {
24+
hydrateAppWithData()
25+
window.app = new Vue(App)
26+
})
27+
.catch(err => console.error(err))
28+
})

0 commit comments

Comments
 (0)