aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--api/routes/github.js2
-rw-r--r--api/services/github/api.js9
-rw-r--r--api/services/github/installations.js21
-rw-r--r--application/components/app.vue24
-rw-r--r--application/components/initialize.vue95
-rw-r--r--package-lock.json14
-rw-r--r--package.json1
7 files changed, 149 insertions, 17 deletions
diff --git a/api/routes/github.js b/api/routes/github.js
index 9594b5c..a1f23b4 100644
--- a/api/routes/github.js
+++ b/api/routes/github.js
@@ -73,7 +73,7 @@ const getInstallation = async (req, res, next) => {
return res.json({ installation: null })
}
- const { data: { repositories } } = await fetchInstallationRepos(user.oauth_access_token, installation.id)
+ const repositories = await fetchInstallationRepos(user.oauth_access_token, installation.id)
res.json({ installation, repositories })
} catch (err) {
diff --git a/api/services/github/api.js b/api/services/github/api.js
index b9bf600..bfaad61 100644
--- a/api/services/github/api.js
+++ b/api/services/github/api.js
@@ -1,7 +1,8 @@
const axios = require('axios')
const baseUrl = 'https://api.github.com'
-function request (options={}) {
+
+async function request (options={}) {
if (typeof options === 'string') {
options = {
url: options
@@ -20,7 +21,11 @@ function request (options={}) {
options.headers.Authorization = `Bearer ${options.token}`
}
- return axios(options)
+ const response = await axios(options)
+
+ console.log(response.headers['x-ratelimit-remaining'])
+
+ return response
}
module.exports = {
diff --git a/api/services/github/installations.js b/api/services/github/installations.js
index 73b1764..346dc45 100644
--- a/api/services/github/installations.js
+++ b/api/services/github/installations.js
@@ -1,3 +1,5 @@
+const linkHeader = require('http-link-header')
+
const api = require('./api')
const { createAppToken } = require('./auth')
@@ -12,11 +14,20 @@ function fetchInstallation (user) {
})
}
-function fetchInstallationRepos (installationToken, installationId) {
- return api.request({
- url: `/user/installations/${installationId}/repositories`,
- token: installationToken
- })
+async function fetchInstallationRepos (installationToken, installationId) {
+ const initialPage = `/user/installations/${installationId}/repositories`
+ const repositories = []
+
+ let url = initialPage
+ while (url) {
+ console.log('fetching page', url)
+ const { headers, data } = await api.request({ url, token: installationToken })
+ const paging = linkHeader.parse(headers.link || '')
+ repositories.push(...data.repositories)
+ url = paging.get('rel', 'next')?.[0]?.uri
+ }
+
+ return repositories
}
module.exports = {
diff --git a/application/components/app.vue b/application/components/app.vue
index 6aed63d..ac4348d 100644
--- a/application/components/app.vue
+++ b/application/components/app.vue
@@ -1,6 +1,6 @@
<script>
-import keyBy from 'lodash/keyBy'
+import Initialize from './initialize.vue'
import Keymap from './keymap.vue'
import Loader from './loader.vue'
import Modal from './modal.vue'
@@ -8,14 +8,10 @@ import Modal from './modal.vue'
import * as config from '../config'
import * as github from '../github'
-import { healthcheck, loadBehaviours } from '../api'
-import { loadLayout } from '../layout.js'
-import { loadKeymap } from '../keymap.js'
-import { loadKeycodes } from '../keycodes'
-
export default {
components: {
keymap: Keymap,
+ Initialize,
Loader,
Modal
},
@@ -131,7 +127,7 @@ export default {
</script>
<template>
- <loader :load="doReadyCheck">
+ <initialize v-slot="{ keymap, layout }">
<div v-if="tooManyRepos">
<modal>
<div class="dialog">
@@ -145,6 +141,7 @@ export default {
</div>
</modal>
</div>
+
<div v-else-if="loadKeyboardError === 'InvalidRepoError'">
<modal>
<div class="dialog">
@@ -158,8 +155,13 @@ export default {
</div>
</modal>
</div>
+
<template v-else>
- <keymap :layout="layout" :keymap="editingKeymap.keyboard ? editingKeymap : keymap" @update="handleUpdateKeymap" />
+ <keymap
+ :layout="layout"
+ :keymap="editingKeymap.keyboard ? editingKeymap : keymap"
+ @update="handleUpdateKeymap"
+ />
<div id="actions">
<button
v-if="config.enableLocal"
@@ -168,12 +170,15 @@ export default {
:disabled="!this.editingKeymap.keyboard"
@click="handleCompile"
/>
+
<button
v-if="config.enableGitHub && !githubAuthorized"
v-text="`Authorize GitHub`"
@click="handleGithubAuthorize"
title="Install as a GitHub app to edit a zmk-config repository."
+
/>
+
<button
v-if="config.enableGitHub && githubAuthorized"
v-text="`Commit Changes`"
@@ -183,10 +188,11 @@ export default {
/>
</div>
</template>
+
<a class="github-link" href="https://github.com/nickcoutsos/keymap-editor">
<i class="fab fa-github" />/nickcoutsos/keymap-editor
</a>
- </loader>
+ </initialize>
</template>
<style scoped>
diff --git a/application/components/initialize.vue b/application/components/initialize.vue
new file mode 100644
index 0000000..0622fa7
--- /dev/null
+++ b/application/components/initialize.vue
@@ -0,0 +1,95 @@
+<script>
+import keyBy from 'lodash/keyBy'
+
+import * as config from '../config'
+import * as github from '../github'
+
+import { healthcheck, loadBehaviours } from '../api'
+import { loadLayout } from '../layout.js'
+import { loadKeymap } from '../keymap.js'
+import { loadKeycodes } from '../keycodes'
+
+import Loader from './loader.vue'
+
+export default {
+ name: 'Initialize',
+ components: { Loader },
+ data () {
+ return {
+ keycodes: [],
+ behaviours: [],
+ indexedKeycodes: {},
+ indexedBehaviours: {},
+ repositories: [],
+ selectedRepository: null,
+ keymap: {},
+ layers: [],
+ layout: []
+ }
+ },
+ provide() {
+ return {
+ keycodes: this.keycodes,
+ behaviours: this.behaviours,
+ indexedKeycodes: this.indexedKeycodes,
+ indexedBehaviours: this.indexedBehaviours
+ }
+ },
+ methods: {
+ async doReadyCheck() {
+ await healthcheck()
+ await this.loadAppData()
+ await this.loadKeyboardData()
+ },
+ async loadAppData () {
+ await github.init()
+ const [ keycodes, behaviours ] = await Promise.all([
+ loadKeycodes(),
+ loadBehaviours()
+ ])
+
+ this.keycodes.splice(0, this.keycodes.length, ...keycodes)
+ this.behaviours.splice(0, this.behaviours.length, ...behaviours)
+ Object.assign(this.indexedKeycodes, keyBy(this.keycodes, 'code'))
+ Object.assign(this.indexedBehaviours, keyBy(this.behaviours, 'code'))
+ },
+ async loadKeyboardData() {
+ const loadKeyboardData = async () => {
+ if (config.enableGitHub && github.isGitHubAuthorized()) {
+ return github.fetchLayoutAndKeymap()
+ } else if (config.enableLocal) {
+ const [layout, keymap] = await Promise.all([
+ loadLayout(),
+ loadKeymap()
+ ])
+ return { layout, keymap }
+ } else {
+ return { layout: [], keymap: { layers: [] } }
+ }
+ }
+
+ const { layout, keymap } = await loadKeyboardData()
+
+ this.layout.splice(0, this.layout.length, ...layout.map(key => (
+ { ...key, u: key.u || key.w || 1, h: key.h || 1 }
+ )))
+
+ const layerNames = keymap.layer_names || keymap.layers.map((_, i) => `Layer ${i}`)
+ Object.assign(this.layers, keymap.layers)
+ Object.assign(this.keymap, keymap, {
+ layer_names: layerNames
+ })
+ }
+ }
+}
+</script>
+
+<template>
+ <loader :load="doReadyCheck">
+ <slot
+ :keymap="keymap"
+ :layers="layers"
+ :layout="layout"
+ />
+ </loader>
+</template> \ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index c0a8b7f..1aa391f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"dotenv": "^10.0.0",
"express": "^4.17.1",
"express-ws": "^4.0.0",
+ "http-link-header": "^1.0.3",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"morgan": "^1.10.0"
@@ -323,6 +324,14 @@
"node": ">= 0.6"
}
},
+ "node_modules/http-link-header": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.0.3.tgz",
+ "integrity": "sha512-nARK1wSKoBBrtcoESlHBx36c1Ln/gnbNQi1eB6MeTUefJIT3NvUOsV15bClga0k38f0q/kN5xxrGSDS3EFnm9w==",
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -959,6 +968,11 @@
"toidentifier": "1.0.0"
}
},
+ "http-link-header": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.0.3.tgz",
+ "integrity": "sha512-nARK1wSKoBBrtcoESlHBx36c1Ln/gnbNQi1eB6MeTUefJIT3NvUOsV15bClga0k38f0q/kN5xxrGSDS3EFnm9w=="
+ },
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
diff --git a/package.json b/package.json
index dbf6627..a68c1ff 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"dotenv": "^10.0.0",
"express": "^4.17.1",
"express-ws": "^4.0.0",
+ "http-link-header": "^1.0.3",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21",
"morgan": "^1.10.0"