Refactor web instance to add missing supported plugins options, rename routes and display remaining GitHub requests (#20)

This commit is contained in:
Simon Lecoq
2020-12-14 18:34:28 +01:00
committed by GitHub
parent fefb194536
commit 217be9a1bc
6 changed files with 142 additions and 59 deletions

File diff suppressed because one or more lines are too long

View File

@@ -47,31 +47,25 @@
const actions = {flush:new Map()}
app.get("/", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
app.get("/index.html", limiter, (req, res) => res.sendFile(`${conf.statics}/index.html`))
app.get("/app.js", limiter, (req, res) => res.sendFile(`${conf.statics}/app.js`))
app.get("/style.css", limiter, (req, res) => res.sendFile(`${conf.statics}/style.css`))
app.get("/.version", limiter, (req, res) => res.status(200).send(conf.package.version))
app.get("/favicon.ico", limiter, (req, res) => res.sendStatus(204))
app.get("/plugins.list", limiter, (req, res) => res.status(200).json(enabled))
app.get("/templates.list", limiter, (req, res) => res.status(200).json(templates))
app.get("/plugins.base.parts.list", limiter, (req, res) => res.status(200).json(conf.settings.plugins.base.parts))
app.get("/ejs.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/ejs/ejs.min.js`))
app.get("/axios.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/axios/dist/axios.min.js`))
app.get("/axios.min.map", limiter, (req, res) => res.sendFile(`${conf.node_modules}/axios/dist/axios.min.map`))
app.get("/vue.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/vue/dist/vue.min.js`))
app.get("/vue.prism.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/vue-prism-component/dist/vue-prism-component.min.js`))
app.get("/vue-prism-component.min.js.map", limiter, (req, res) => res.sendFile(`${conf.node_modules}/vue-prism-component/dist/vue-prism-component.min.js.map`))
app.get("/prism.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/prismjs/prism.js`))
app.get("/prism.yaml.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/prismjs/components/prism-yaml.min.js`))
app.get("/prism.markdown.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/prismjs/components/prism-markdown.min.js`))
app.get("/style.prism.css", limiter, (req, res) => res.sendFile(`${conf.node_modules}/prismjs/themes/prism-tomorrow.css`))
app.get("/placeholder.json", limiter, async (req, res) => {
const template = req.query.template || conf.settings.templates.default
if (!(template in Templates))
return res.sendStatus(404)
const {style, image, fonts} = conf.templates[template]
res.status(200).json({style, image, fonts})
})
app.get("/action.flush", limiter, async (req, res) => {
app.get("/.version", limiter, (req, res) => res.status(200).send(conf.package.version))
app.get("/.requests", limiter, async (req, res) => res.status(200).json((await rest.rateLimit.get()).data.rate))
app.get("/.templates", limiter, (req, res) => res.status(200).json(templates))
app.get("/.plugins", limiter, (req, res) => res.status(200).json(enabled))
app.get("/.plugins.base", limiter, (req, res) => res.status(200).json(conf.settings.plugins.base.parts))
app.get("/.css/style.css", limiter, (req, res) => res.sendFile(`${conf.statics}/style.css`))
app.get("/.css/style.prism.css", limiter, (req, res) => res.sendFile(`${conf.node_modules}/prismjs/themes/prism-tomorrow.css`))
app.get("/.js/app.js", limiter, (req, res) => res.sendFile(`${conf.statics}/app.js`))
app.get("/.js/ejs.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/ejs/ejs.min.js`))
app.get("/.js/axios.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/axios/dist/axios.min.js`))
app.get("/.js/axios.min.map", limiter, (req, res) => res.sendFile(`${conf.node_modules}/axios/dist/axios.min.map`))
app.get("/.js/vue.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/vue/dist/vue.min.js`))
app.get("/.js/vue.prism.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/vue-prism-component/dist/vue-prism-component.min.js`))
app.get("/.js/vue-prism-component.min.js.map", limiter, (req, res) => res.sendFile(`${conf.node_modules}/vue-prism-component/dist/vue-prism-component.min.js.map`))
app.get("/.js/prism.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/prismjs/prism.js`))
app.get("/.js/prism.yaml.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/prismjs/components/prism-yaml.min.js`))
app.get("/.js/prism.markdown.min.js", limiter, (req, res) => res.sendFile(`${conf.node_modules}/prismjs/components/prism-markdown.min.js`))
app.get("/.uncache", limiter, async (req, res) => {
const {token, user} = req.query
if (token) {
if (actions.flush.has(token)) {

View File

@@ -1,9 +1,9 @@
;(async function() {
//Init
const url = new URLSearchParams(window.location.search)
const {data:templates} = await axios.get("/templates.list")
const {data:plugins} = await axios.get("/plugins.list")
const {data:base} = await axios.get("/plugins.base.parts.list")
const {data:templates} = await axios.get("/.templates")
const {data:plugins} = await axios.get("/.plugins")
const {data:base} = await axios.get("/.plugins.base")
const {data:version} = await axios.get("/.version")
//App
return new Vue({
@@ -18,6 +18,7 @@
version,
user:url.get("user") || "",
palette:url.get("palette") || (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light") || "light",
requests:{limit:0, used:0, remaining:0, reset:0},
plugins:{
base,
list:plugins,
@@ -45,10 +46,13 @@
"pagespeed.detailed":false,
"habits.from":100,
"music.playlist":"",
"music.mode":"playlist",
"music.limit":4,
"posts.limit":4,
"posts.source":"dev.to",
"isocalendar.duration":"half-year",
"projects.limit":4,
"topics.sort":"stars",
"topics.limit":12,
},
},
templates:{
@@ -130,6 +134,8 @@
const url = this.url.replace(new RegExp(`${this.user}(\\?|$)`), "placeholder$1")
this.templates.placeholder = this.serialize((await axios.get(url)).data)
this.generated.content = ""
//Start GitHub rate limiter tracker
this.ghlimit()
},
//Generate metrics and flush cache
async generate() {
@@ -139,7 +145,7 @@
this.generated.pending = true
//Compute metrics
try {
await axios.get(`/action.flush?&token=${(await axios.get(`/action.flush?user=${this.user}`)).data.token}`)
await axios.get(`/.uncache?&token=${(await axios.get(`/.uncache?user=${this.user}`)).data.token}`)
this.generated.content = this.serialize((await axios.get(this.url)).data)
} catch {
this.generated.error = true
@@ -152,6 +158,13 @@
serialize(svg) {
return `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svg)))}`
},
//Update reate limit requests
async ghlimit() {
const {data:requests} = await axios.get("/.requests")
this.requests = requests
setTimeout(() => this.ghlimit(), 30*1000)
console.log("yeh")
}
},
})
})()

View File

@@ -6,8 +6,8 @@
<meta name="description" content="A SVG image generator which includes activity, community and repositories metrics about your GitHub account that you can includes on your profile">
<meta name="author" content="lowlighter">
<link rel="icon" href="data:,">
<link rel="stylesheet" href="/style.css">
<link rel="stylesheet" href="/style.prism.css" />
<link rel="stylesheet" href="/.css/style.css">
<link rel="stylesheet" href="/.css/style.prism.css" />
</head>
<body>
<!-- Vue app -->
@@ -51,25 +51,80 @@
</label>
</div>
<i>*Additional plugins may be available when used as GitHub Action</i>
<template v-if="(plugins.enabled.pagespeed)||(plugins.enabled.habits)||(plugins.enabled.music)||(plugins.enabled.posts)">
<template v-if="(plugins.enabled.music)||(plugins.enabled.pagespeed)||(plugins.enabled.habits)||(plugins.enabled.posts)||(plugins.enabled.isocalendar)||(plugins.enabled.projects)||(plugins.enabled.topics)">
<h3>2.3 Configure additional plugins</h3>
<div class="options">
<label v-if="plugins.enabled.pagespeed">
Detailed PageSpeed report
<input type="checkbox" v-model="plugins.options['pagespeed.detailed']" @change="load">
</label>
<label v-if="(plugins.enabled.music)&&(plugins.options['music.mode'] === 'playlist')">
<div class="options-group" v-if="plugins.enabled.music">
<h4>{{ plugins.descriptions.music }}</h4>
<label>
Playlist embed link
<input type="text" v-model="plugins.options['music.playlist']" placeholder="https://embed.music.apple.com/en/playlist/">
</label>
<label v-if="plugins.enabled.habits">
<label>
Number of tracks to display
<input type="number" v-model="plugins.options['music.limit']" min="1" @change="load">
</label>
</div>
<div class="options-group" v-if="plugins.enabled.pagespeed">
<h4>{{ plugins.descriptions.pagespeed }}</h4>
<label>
Detailed PageSpeed report
<input type="checkbox" v-model="plugins.options['pagespeed.detailed']" @change="load">
</label>
</div>
<div class="options-group" v-if="plugins.enabled.habits">
<h4>{{ plugins.descriptions.habits }}</h4>
<label>
Number of events for habits
<input type="number" v-model="plugins.options['habits.from']" min="1" max="100">
</label>
<label v-if="plugins.enabled.posts">
</div>
<div class="options-group" v-if="plugins.enabled.posts">
<h4>{{ plugins.descriptions.posts }}</h4>
<label>
Posts source
<input type="text" v-model="plugins.options['posts.source']" disabled>
<select v-model="plugins.options['posts.source']" disabled>
<option value="dev.to">dev.to</option>
</select>
</label>
<label>
Number of posts to display
<input type="number" v-model="plugins.options['posts.limit']" min="1" @change="load">
</label>
</div>
<div class="options-group" v-if="plugins.enabled.isocalendar">
<h4>{{ plugins.descriptions.isocalendar }}</h4>
<label>
Isocalendar duration
<select v-model="plugins.options['isocalendar.duration']">
<option value="half-year">Half year</option>
<option value="full-year">Full year</option>
</select>
</label>
</div>
<div class="options-group" v-if="plugins.enabled.topics">
<h4>{{ plugins.descriptions.topics }}</h4>
<label>
Topics sorting
<select v-model="plugins.options['topics.sort']">
<option value="starred">Recently starred by you</option>
<option value="stars">Most stars</option>
<option value="activity">Recent actity</option>
<option value="random">Random</option>
</select>
</label>
<label>
Number of topics to display
<input type="number" v-model="plugins.options['topics.limit']" @change="load">
</label>
</div>
<div class="options-group" v-if="plugins.enabled.projects">
<h4>{{ plugins.descriptions.projects }}</h4>
<label>
Number of projects to display
<input type="number" v-model="plugins.options['projects.limit']" min="1" max="100" @change="load">
</label>
</div>
</div>
</template>
</template>
@@ -128,15 +183,19 @@
</section>
</section>
</template>
<!-- GitHub requests tracker -->
<template>
<div class="gh-requests">{{ requests.remaining }} GitHub request{{ requests.remaining > 1 ? "s" : "" }} remaining</div>
</template>
</main>
<!-- Scripts -->
<script src="/axios.min.js"></script>
<script src="/prism.min.js"></script>
<script src="/prism.markdown.min.js"></script>
<script src="/prism.yaml.min.js"></script>
<script src="/ejs.min.js"></script>
<script src="/vue.min.js"></script>
<script src="/vue.prism.min.js"></script>
<script src="/app.js"></script>
<script src="/.js/axios.min.js"></script>
<script src="/.js/prism.min.js"></script>
<script src="/.js/prism.markdown.min.js"></script>
<script src="/.js/prism.yaml.min.js"></script>
<script src="/.js/ejs.min.js"></script>
<script src="/.js/vue.min.js"></script>
<script src="/.js/vue.prism.min.js"></script>
<script src="/.js/app.js"></script>
</body>
</html>

View File

@@ -142,6 +142,16 @@
display: flex;
flex-direction: column;
}
.options-group {
display: flex;
flex-direction: column;
}
.options-group label {
margin: 0;
}
.options-group h4 {
margin-bottom: 0;
}
/* Code snippets */
.code {
display: flex;
@@ -194,3 +204,10 @@
justify-content: center;
align-items: center;
}
/* Github requests */
.gh-requests {
position: fixed;
right: .25rem;
bottom: .25rem;
font-size: .8rem;
}

View File

@@ -167,8 +167,8 @@
followup:{issues:{count:0}, pr:{count:0}},
habits:{indents:{style:`########`}},
languages:{favorites:new Array(7).fill(null).map((_, x) => ({x, name:"######", color:"#ebedf0", value:1/(x+1)}))},
topics:{list:[...new Array(12).fill(null).map(() => ({name:"######", description:"", icon:null})), {name:`And ## more...`, description:"", icon:null}]},
projects:{list:[...new Array(4).fill(null).map(() => ({name:"########", updated:"########", progress:{enabled:true, todo:"##", doing:"##", done:"##", total:"##"}}))]},
topics:{list:[...new Array("topics.limit" in q ? Math.max(Number(q["topics.limit"])||0, 0) : 12).fill(null).map(() => ({name:"######", description:"", icon:null})), {name:`And ## more...`, description:"", icon:null}]},
projects:{list:[...new Array("projects.limit" in q ? Math.max(Number(q["projects.limit"])||0, 0) : 4).fill(null).map(() => ({name:"########", updated:"########", progress:{enabled:true, todo:"##", doing:"##", done:"##", total:"##"}}))]},
}[key]??{})]
)),
})