feature: commit dialog for upgradeable components
Signed-off-by: Stefan Dej <meteyou@gmail.com>
This commit is contained in:
parent
a0d21f6664
commit
f2ea6c039f
87
package-lock.json
generated
87
package-lock.json
generated
@ -15,6 +15,7 @@
|
||||
"object-assign-deep": "^0.4.0",
|
||||
"plotly.js": "^1.58.4",
|
||||
"prismjs": "^1.23.0",
|
||||
"semver": "^5.7.1",
|
||||
"vue": "^2.6.12",
|
||||
"vue-context": "^6.0.0",
|
||||
"vue-github-api": "^0.1.7",
|
||||
@ -2282,7 +2283,6 @@
|
||||
"thread-loader": "^2.1.3",
|
||||
"url-loader": "^2.2.0",
|
||||
"vue-loader": "^15.9.2",
|
||||
"vue-loader-v16": "npm:vue-loader@^16.1.0",
|
||||
"vue-style-loader": "^4.1.2",
|
||||
"webpack": "^4.0.0",
|
||||
"webpack-bundle-analyzer": "^3.8.0",
|
||||
@ -2581,7 +2581,6 @@
|
||||
"merge-source-map": "^1.1.0",
|
||||
"postcss": "^7.0.14",
|
||||
"postcss-selector-parser": "^6.0.2",
|
||||
"prettier": "^1.18.2",
|
||||
"source-map": "~0.6.1",
|
||||
"vue-template-es2015-compiler": "^1.9.0"
|
||||
},
|
||||
@ -4312,7 +4311,6 @@
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.1",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.1.2",
|
||||
"glob-parent": "~5.1.0",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
@ -6700,8 +6698,7 @@
|
||||
"esprima": "^4.0.1",
|
||||
"estraverse": "^4.2.0",
|
||||
"esutils": "^2.0.2",
|
||||
"optionator": "^0.8.1",
|
||||
"source-map": "~0.6.1"
|
||||
"optionator": "^0.8.1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"source-map": "~0.6.1"
|
||||
@ -7812,7 +7809,72 @@
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz",
|
||||
"integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==",
|
||||
"bundleDependencies": [
|
||||
"node-pre-gyp"
|
||||
"node-pre-gyp",
|
||||
"abbrev",
|
||||
"ansi-regex",
|
||||
"aproba",
|
||||
"are-we-there-yet",
|
||||
"balanced-match",
|
||||
"brace-expansion",
|
||||
"chownr",
|
||||
"code-point-at",
|
||||
"concat-map",
|
||||
"console-control-strings",
|
||||
"core-util-is",
|
||||
"debug",
|
||||
"deep-extend",
|
||||
"delegates",
|
||||
"detect-libc",
|
||||
"fs-minipass",
|
||||
"fs.realpath",
|
||||
"gauge",
|
||||
"glob",
|
||||
"has-unicode",
|
||||
"iconv-lite",
|
||||
"ignore-walk",
|
||||
"inflight",
|
||||
"inherits",
|
||||
"ini",
|
||||
"is-fullwidth-code-point",
|
||||
"isarray",
|
||||
"minimatch",
|
||||
"minimist",
|
||||
"minipass",
|
||||
"minizlib",
|
||||
"mkdirp",
|
||||
"ms",
|
||||
"needle",
|
||||
"nopt",
|
||||
"npm-bundled",
|
||||
"npm-normalize-package-bin",
|
||||
"npm-packlist",
|
||||
"npmlog",
|
||||
"number-is-nan",
|
||||
"object-assign",
|
||||
"once",
|
||||
"os-homedir",
|
||||
"os-tmpdir",
|
||||
"osenv",
|
||||
"path-is-absolute",
|
||||
"process-nextick-args",
|
||||
"rc",
|
||||
"readable-stream",
|
||||
"rimraf",
|
||||
"safe-buffer",
|
||||
"safer-buffer",
|
||||
"sax",
|
||||
"semver",
|
||||
"set-blocking",
|
||||
"signal-exit",
|
||||
"string_decoder",
|
||||
"string-width",
|
||||
"strip-ansi",
|
||||
"strip-json-comments",
|
||||
"tar",
|
||||
"util-deprecate",
|
||||
"wide-align",
|
||||
"wrappy",
|
||||
"yallist"
|
||||
],
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
@ -13517,9 +13579,6 @@
|
||||
"version": "1.23.0",
|
||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.23.0.tgz",
|
||||
"integrity": "sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==",
|
||||
"dependencies": {
|
||||
"clipboard": "^2.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"clipboard": "^2.0.0"
|
||||
}
|
||||
@ -14721,8 +14780,7 @@
|
||||
"node_modules/semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||
},
|
||||
"node_modules/semver-diff": {
|
||||
"version": "2.1.0",
|
||||
@ -17595,8 +17653,7 @@
|
||||
"dependencies": {
|
||||
"chokidar": "^3.4.1",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"neo-async": "^2.5.0",
|
||||
"watchpack-chokidar2": "^2.0.0"
|
||||
"neo-async": "^2.5.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"watchpack-chokidar2": "^2.0.0"
|
||||
@ -17812,7 +17869,6 @@
|
||||
"anymatch": "^2.0.0",
|
||||
"async-each": "^1.0.1",
|
||||
"braces": "^2.3.2",
|
||||
"fsevents": "^1.2.7",
|
||||
"glob-parent": "^3.1.0",
|
||||
"inherits": "^2.0.3",
|
||||
"is-binary-path": "^1.0.0",
|
||||
@ -32563,8 +32619,7 @@
|
||||
"semver": {
|
||||
"version": "5.7.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||
},
|
||||
"semver-diff": {
|
||||
"version": "2.1.0",
|
||||
|
@ -16,6 +16,7 @@
|
||||
"object-assign-deep": "^0.4.0",
|
||||
"plotly.js": "^1.58.4",
|
||||
"prismjs": "^1.23.0",
|
||||
"semver": "^5.7.1",
|
||||
"vue": "^2.6.12",
|
||||
"vue-context": "^6.0.0",
|
||||
"vue-github-api": "^0.1.7",
|
||||
|
@ -1,73 +1,120 @@
|
||||
<template>
|
||||
<v-card>
|
||||
<v-toolbar flat dense >
|
||||
<v-toolbar-title>
|
||||
<span class="subheading"><v-icon left>mdi-update</v-icon>Update Manager</span>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-tooltip top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn small class="px-2 minwidth-0" color="primary" :loading="loadings.includes('loadingBtnSyncUpdateManager')" :disabled="['printing', 'paused'].includes(printer_state)" @click="btnSync" v-bind="attrs" v-on="on"><v-icon small>mdi-refresh</v-icon></v-btn>
|
||||
</template>
|
||||
<span>Check for updates</span>
|
||||
</v-tooltip>
|
||||
</v-toolbar>
|
||||
<v-card-text class="px-0 py-0">
|
||||
<v-container py-0 px-0>
|
||||
<style scoped>
|
||||
.cursor--pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div v-for="(value, key) of updateableSoftwares" v-bind:key="key">
|
||||
<v-divider class="my-0" ></v-divider>
|
||||
<v-row class="py-2">
|
||||
<v-col class="pl-6">
|
||||
{{ 'name' in value ? value.name : key }}<br />
|
||||
{{ getVersionOutput(value) }}
|
||||
</v-col>
|
||||
<v-col class="col-auto pr-6 text-right" align-self="center">
|
||||
<v-chip
|
||||
small
|
||||
label
|
||||
outlined
|
||||
:color="getBtnColor(value)"
|
||||
@click="updateModule(key)"
|
||||
:disabled="getBtnDisabled(value)"
|
||||
class="minwidth-0 px-2 text-uppercase"
|
||||
><v-icon small class="mr-1">mdi-{{ getBtnIcon(value) }}</v-icon>{{ getBtnText(value) }}</v-chip>
|
||||
<template>
|
||||
<div>
|
||||
<v-card>
|
||||
<v-toolbar flat dense >
|
||||
<v-toolbar-title>
|
||||
<span class="subheading"><v-icon left>mdi-update</v-icon>Update Manager</span>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-tooltip top>
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<v-btn small class="px-2 minwidth-0" color="primary" :loading="loadings.includes('loadingBtnSyncUpdateManager')" :disabled="['printing', 'paused'].includes(printer_state)" @click="btnSync" v-bind="attrs" v-on="on"><v-icon small>mdi-refresh</v-icon></v-btn>
|
||||
</template>
|
||||
<span>Check for updates</span>
|
||||
</v-tooltip>
|
||||
</v-toolbar>
|
||||
<v-card-text class="px-0 py-0">
|
||||
<v-container py-0 px-0>
|
||||
|
||||
<div v-for="(value, key) of updateableSoftwares" v-bind:key="key">
|
||||
<v-divider class="my-0" ></v-divider>
|
||||
<v-row class="py-2">
|
||||
<v-col class="pl-6">
|
||||
<strong>{{ 'name' in value ? value.name : key }}</strong><br />
|
||||
<span @click="openCommitsOverlay(key, value)" :class="getVersionClickable(value) ? 'primary--text cursor--pointer' : ''">{{ getVersionOutput(value) }}</span>
|
||||
</v-col>
|
||||
<v-col class="col-auto pr-6 text-right" align-self="center">
|
||||
<v-chip
|
||||
small
|
||||
label
|
||||
outlined
|
||||
:color="getBtnColor(value)"
|
||||
@click="updateModule(key)"
|
||||
:disabled="getBtnDisabled(value)"
|
||||
class="minwidth-0 px-2 text-uppercase"
|
||||
><v-icon small class="mr-1">mdi-{{ getBtnIcon(value) }}</v-icon>{{ getBtnText(value) }}</v-chip>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
<div v-if="'system' in version_info">
|
||||
<v-divider class="my-0 border-top-2" ></v-divider>
|
||||
<v-row class="pt-2">
|
||||
<v-col class="col-auto pl-6 text-no-wrap">
|
||||
<strong>System</strong><br />
|
||||
<v-tooltip top v-if="version_info.system.package_count > 0" :max-width="300">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<span v-bind="attrs" v-on="on">{{ version_info.system.package_count }} packages can be upgraded</span>
|
||||
</template>
|
||||
<span>{{ version_info.system.package_list.join(', ') }}</span>
|
||||
</v-tooltip>
|
||||
<span v-if="version_info.system.package_count === 0">OS-Packages</span>
|
||||
</v-col>
|
||||
<v-col class="pr-6 text-right" align-self="center">
|
||||
<v-chip
|
||||
small
|
||||
label
|
||||
outlined
|
||||
:color="version_info.system.package_count ? 'primary' : 'green'"
|
||||
:disabled="!(version_info.system.package_count) || printer_state === 'printing'"
|
||||
@click="updateSystem"
|
||||
class="minwidth-0 px-2 text-uppercase"
|
||||
><v-icon small class="mr-1">mdi-{{ version_info.system.package_count ? 'progress-upload' : 'check' }}</v-icon>{{ version_info.system.package_count ? 'upgrade' : 'up-to-date' }}</v-chip>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
<v-dialog v-model="commitsOverlay.bool" persistent width="60%" max-width="800">
|
||||
<v-card dark>
|
||||
<v-toolbar flat dense >
|
||||
<v-toolbar-title>
|
||||
<span class="subheading"><v-icon left>mdi-update</v-icon>Commits</span>
|
||||
</v-toolbar-title>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn small class="minwidth-0" color="grey darken-3" @click="commitsOverlay.bool = false"><v-icon small>mdi-close-thick</v-icon></v-btn>
|
||||
</v-toolbar>
|
||||
<v-card-text class="py-5" v-if="commitsOverlay.loading">
|
||||
<v-row class="pt-0">
|
||||
<v-col>
|
||||
<v-progress-linear color="primary" indeterminate></v-progress-linear>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
<div v-if="'system' in version_info">
|
||||
<v-divider class="my-0 border-top-2" ></v-divider>
|
||||
<v-row class="pt-2">
|
||||
<v-col class="col-auto pl-6 text-no-wrap">
|
||||
<strong>System</strong><br />
|
||||
<v-tooltip top v-if="version_info.system.package_count > 0" :max-width="300">
|
||||
<template v-slot:activator="{ on, attrs }">
|
||||
<span v-bind="attrs" v-on="on">{{ version_info.system.package_count }} packages can be upgraded</span>
|
||||
</template>
|
||||
<span>{{ version_info.system.package_list.join(', ') }}</span>
|
||||
</v-tooltip>
|
||||
<span v-if="version_info.system.package_count === 0">OS-Packages</span>
|
||||
</v-col>
|
||||
<v-col class="pr-6 text-right" align-self="center">
|
||||
<v-chip
|
||||
small
|
||||
label
|
||||
outlined
|
||||
:color="version_info.system.package_count ? 'primary' : 'green'"
|
||||
:disabled="!(version_info.system.package_count) || printer_state === 'printing'"
|
||||
@click="updateSystem"
|
||||
class="minwidth-0 px-2 text-uppercase"
|
||||
><v-icon small class="mr-1">mdi-{{ version_info.system.package_count ? 'progress-upload' : 'check' }}</v-icon>{{ version_info.system.package_count ? 'upgrade' : 'up-to-date' }}</v-chip>
|
||||
</v-card-text>
|
||||
<v-card-text class="py-0" v-if="!commitsOverlay.loading" style="max-height: 400px; overflow-y: scroll;">
|
||||
<v-row>
|
||||
<v-col class="pt-3 pl-0">
|
||||
<v-timeline align-top dense >
|
||||
<v-timeline-item color="primary" small v-for="commit of commitsOverlay.outputs" v-bind:key="commit.sha">
|
||||
<v-row class="pt-0">
|
||||
<v-col>
|
||||
<a class="font-weight-bold white--text" :href="commit.url" target="_blank">{{ commit.title }}</a><br />
|
||||
<p v-if="commit.message" class="mb-0" v-html="commit.message.replace(/(?:\r\n|\r|\n)/g, '<br />')"></p>
|
||||
<div class="caption">
|
||||
<strong>{{ commit.author }}</strong> committed at {{ commit.date.toLocaleString() }}
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-timeline-item>
|
||||
</v-timeline>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import { mapState } from 'vuex'
|
||||
import semver from 'semver'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -75,12 +122,16 @@
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
|
||||
commitsOverlay: {
|
||||
bool: false,
|
||||
loading: false,
|
||||
response: [],
|
||||
outputs: [],
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
package_version: state => state.packageVersion,
|
||||
loadings: state => state.socket.loadings,
|
||||
remoteMode: state => state.socket.remoteMode,
|
||||
printer_state: state => state.printer.print_stats.state,
|
||||
@ -103,7 +154,7 @@
|
||||
if ('is_dirty' in object && object.is_dirty) return 'orange'
|
||||
if ('is_valid' in object && !object.is_valid) return 'red'
|
||||
|
||||
if ('version' in object && 'remote_version' in object && object.version !== object.remote_version) return 'primary'
|
||||
if ('version' in object && 'remote_version' in object && semver.gt(object.remote_version, object.version)) return 'primary'
|
||||
|
||||
return 'green'
|
||||
}
|
||||
@ -116,7 +167,7 @@
|
||||
if ('is_valid' in object && !object.is_valid) return 'invalid'
|
||||
if ('is_dirty' in object && object.is_dirty) return 'dirty'
|
||||
|
||||
if ('version' in object && 'remote_version' in object && object.version !== object.remote_version) return 'update'
|
||||
if ('version' in object && 'remote_version' in object && semver.gt(object.remote_version, object.version)) return 'update'
|
||||
|
||||
return 'up-to-date'
|
||||
}
|
||||
@ -129,7 +180,7 @@
|
||||
if ('is_valid' in object && !object.is_valid) return 'alert-circle'
|
||||
if ('is_dirty' in object && object.is_dirty) return 'alert-circle'
|
||||
|
||||
if ('version' in object && 'remote_version' in object && object.version !== object.remote_version) return 'progress-upload'
|
||||
if ('version' in object && 'remote_version' in object && semver.gt(object.remote_version, object.version)) return 'progress-upload'
|
||||
|
||||
return 'check'
|
||||
}
|
||||
@ -142,7 +193,7 @@
|
||||
|
||||
if (typeof object === 'object' && object !== false) {
|
||||
if ('is_valid' in object && !object.is_valid) return true
|
||||
if ('version' in object && 'remote_version' in object && object.version !== object.remote_version) return false
|
||||
if ('version' in object && 'remote_version' in object && semver.gt(object.remote_version, object.version)) return false
|
||||
}
|
||||
|
||||
return true
|
||||
@ -160,10 +211,19 @@
|
||||
}
|
||||
if (output !== "") output += ": "
|
||||
|
||||
output += local_version !== remote_version ? local_version+" > "+remote_version : local_version
|
||||
output += semver.gt(remote_version, local_version) ? local_version+" > "+remote_version : local_version
|
||||
|
||||
return output
|
||||
},
|
||||
getVersionClickable(object) {
|
||||
return (
|
||||
'branch' in object &&
|
||||
object.branch === "master" &&
|
||||
'current_hash' in object &&
|
||||
'remote_hash' in object &&
|
||||
object.current_hash !== object.remote_hash
|
||||
)
|
||||
},
|
||||
updateModule(key) {
|
||||
if (["klipper", "moonraker"].includes(key)) this.$socket.sendObj('machine.update.'+key, { })
|
||||
else this.$socket.sendObj('machine.update.client', { name: key })
|
||||
@ -171,6 +231,70 @@
|
||||
updateSystem() {
|
||||
this.$socket.sendObj('machine.update.system', { })
|
||||
},
|
||||
openCommitsOverlay(key, object) {
|
||||
if (
|
||||
['klipper', 'moonraker'].includes(key) &&
|
||||
this.getVersionClickable(object)
|
||||
) {
|
||||
this.commitsOverlay.bool = true
|
||||
this.commitsOverlay.loading = true
|
||||
|
||||
let owner = ""
|
||||
switch(key) {
|
||||
case 'klipper':
|
||||
owner = "kevinOConnor"
|
||||
break
|
||||
|
||||
case 'moonraker':
|
||||
owner = "arksine"
|
||||
break
|
||||
}
|
||||
|
||||
const apiUrl = "https://api.github.com/repos/"+owner+"/"+key+"/commits"
|
||||
if (apiUrl) {
|
||||
axios
|
||||
.get(apiUrl)
|
||||
.then(response => {
|
||||
this.commitsOverlay.response = response
|
||||
this.commitsOverlay.outputs.splice(0, this.commitsOverlay.outputs.length)
|
||||
|
||||
const index = response.data.findIndex(commit => commit.sha === object.current_hash)
|
||||
if (index !== -1) {
|
||||
this.commitsOverlay.response = response.data.splice(0, index).sort((a,b) => {
|
||||
const dataA = new Date(a.commit.author.date)
|
||||
const dataB = new Date(b.commit.author.date)
|
||||
|
||||
return dataB - dataA
|
||||
})
|
||||
|
||||
this.commitsOverlay.response.forEach(commit => {
|
||||
const date = new Date(commit.commit.author.date)
|
||||
const author = commit.commit.author.name
|
||||
|
||||
const firstIndex = commit.commit.message.indexOf('\n\n')
|
||||
let lastIndex = commit.commit.message.lastIndexOf('\n\n')
|
||||
if (firstIndex === lastIndex && commit.commit.message.lastIndexOf('\r') > firstIndex) {
|
||||
lastIndex = commit.commit.message.lastIndexOf('\r')
|
||||
}
|
||||
|
||||
this.commitsOverlay.outputs.push({
|
||||
sha: commit.sha,
|
||||
date: date,
|
||||
author: author,
|
||||
url: commit.html_url,
|
||||
title: commit.commit.message.substr(0, firstIndex),
|
||||
message: (firstIndex+2 < lastIndex-2) ? commit.commit.message.substr(firstIndex+2, lastIndex-firstIndex-2) : "",
|
||||
firstIndex: firstIndex,
|
||||
lastIndex: lastIndex,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
this.commitsOverlay.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
Loading…
x
Reference in New Issue
Block a user