Allowing "Known remotes" to be import and exported
This commit is contained in:
@@ -32,6 +32,26 @@ export class History {
|
|||||||
this.saver = saver;
|
this.saver = saver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the index of given uname, or -1 when not found
|
||||||
|
*
|
||||||
|
* @param {string} uname the unique name
|
||||||
|
*
|
||||||
|
* @returns {integer} The index of given uname
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
indexOf(uname) {
|
||||||
|
for (let i in this.records) {
|
||||||
|
if (this.records[i].uname !== uname) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save record to history
|
* Save record to history
|
||||||
*
|
*
|
||||||
@@ -44,13 +64,10 @@ export class History {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
save(uname, title, lastUsed, info, data, sessionData) {
|
save(uname, title, lastUsed, info, data, sessionData) {
|
||||||
for (let i in this.records) {
|
const unameIdx = this.indexOf(uname);
|
||||||
if (this.records[i].uname !== uname) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.records.splice(i, 1);
|
if (unameIdx >= 0) {
|
||||||
break;
|
this.records.splice(unameIdx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.records.push({
|
this.records.push({
|
||||||
@@ -78,20 +95,7 @@ export class History {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
store() {
|
store() {
|
||||||
let r = [];
|
this.saver(this, this.export());
|
||||||
|
|
||||||
for (let i in this.records) {
|
|
||||||
r.push({
|
|
||||||
uname: this.records[i].uname,
|
|
||||||
title: this.records[i].title,
|
|
||||||
type: this.records[i].type,
|
|
||||||
color: this.records[i].color,
|
|
||||||
last: this.records[i].last,
|
|
||||||
data: this.records[i].data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.saver(this, r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -131,7 +135,8 @@ export class History {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return all history records
|
* Return all history records. The exported data is differ than the
|
||||||
|
* internal ones, it cannot be directly import back
|
||||||
*
|
*
|
||||||
* @returns {array<object>} Records
|
* @returns {array<object>} Records
|
||||||
*
|
*
|
||||||
@@ -153,4 +158,52 @@ export class History {
|
|||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export current history records
|
||||||
|
*
|
||||||
|
* @returns {array<object>} Records
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export() {
|
||||||
|
let r = [];
|
||||||
|
|
||||||
|
for (let i in this.records) {
|
||||||
|
r.push({
|
||||||
|
uname: this.records[i].uname,
|
||||||
|
title: this.records[i].title,
|
||||||
|
type: this.records[i].type,
|
||||||
|
color: this.records[i].color,
|
||||||
|
last: this.records[i].last,
|
||||||
|
data: this.records[i].data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import data into current history records
|
||||||
|
*
|
||||||
|
* @param {array<object>} records Records
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
import(records) {
|
||||||
|
for (let i in records) {
|
||||||
|
if (this.indexOf(records[i].uname) >= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.records.push({
|
||||||
|
uname: records[i].uname,
|
||||||
|
title: records[i].title,
|
||||||
|
type: records[i].type,
|
||||||
|
color: records[i].color,
|
||||||
|
last: records[i].last,
|
||||||
|
data: records[i].data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.store();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,6 +112,8 @@
|
|||||||
:connectors="connector.connectors"
|
:connectors="connector.connectors"
|
||||||
:knowns="connector.knowns"
|
:knowns="connector.knowns"
|
||||||
:knowns-launcher-builder="buildknownLauncher"
|
:knowns-launcher-builder="buildknownLauncher"
|
||||||
|
:knowns-export="exportKnowns"
|
||||||
|
:knowns-import="importKnowns"
|
||||||
:busy="connector.busy"
|
:busy="connector.busy"
|
||||||
@display="windows.connect = $event"
|
@display="windows.connect = $event"
|
||||||
@connector-select="connectNew"
|
@connector-select="connectNew"
|
||||||
@@ -438,6 +440,12 @@ export default {
|
|||||||
|
|
||||||
return this.hostPath + "#+" + connector.launcher(known.data);
|
return this.hostPath + "#+" + connector.launcher(known.data);
|
||||||
},
|
},
|
||||||
|
exportKnowns() {
|
||||||
|
return this.connector.historyRec.export();
|
||||||
|
},
|
||||||
|
importKnowns(d) {
|
||||||
|
return this.connector.historyRec.import(d);
|
||||||
|
},
|
||||||
removeKnown(uid) {
|
removeKnown(uid) {
|
||||||
this.connector.historyRec.del(uid);
|
this.connector.historyRec.del(uid);
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,8 @@
|
|||||||
v-if="tab === 'known' && !inputting"
|
v-if="tab === 'known' && !inputting"
|
||||||
:knowns="knowns"
|
:knowns="knowns"
|
||||||
:launcher-builder="knownsLauncherBuilder"
|
:launcher-builder="knownsLauncherBuilder"
|
||||||
|
:knowns-export="knownsExport"
|
||||||
|
:knowns-import="knownsImport"
|
||||||
@select="selectKnown"
|
@select="selectKnown"
|
||||||
@remove="removeKnown"
|
@remove="removeKnown"
|
||||||
@clear-session="clearSessionKnown"
|
@clear-session="clearSessionKnown"
|
||||||
@@ -106,6 +108,14 @@ export default {
|
|||||||
type: Function,
|
type: Function,
|
||||||
default: () => []
|
default: () => []
|
||||||
},
|
},
|
||||||
|
knownsExport: {
|
||||||
|
type: Function,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
knownsImport: {
|
||||||
|
type: Function,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
connectors: {
|
connectors: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
|||||||
@@ -24,6 +24,34 @@
|
|||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
background: #3a3a3a;
|
background: #3a3a3a;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
#connect-known-list-list,
|
||||||
|
#connect-known-list-empty {
|
||||||
|
flex: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#connect-known-list-empty {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
font-size: 1.2em;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#connect-known-list-import {
|
||||||
|
margin: 15px 0 10px 0;
|
||||||
|
color: #aaa;
|
||||||
|
font-size: 1.1em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#connect-known-list-import a {
|
||||||
|
color: #e9a;
|
||||||
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#connect-known-list li {
|
#connect-known-list li {
|
||||||
|
|||||||
@@ -19,7 +19,10 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="connect-known-list">
|
<div id="connect-known-list">
|
||||||
<ul class="hlst lstcl1">
|
<div v-if="knownList.length <= 0" id="connect-known-list-empty">
|
||||||
|
No known remote available
|
||||||
|
</div>
|
||||||
|
<ul v-else id="connect-known-list-list" class="hlst lstcl1">
|
||||||
<li v-for="(known, kk) in knownList" :key="kk">
|
<li v-for="(known, kk) in knownList" :key="kk">
|
||||||
<div class="labels">
|
<div class="labels">
|
||||||
<span class="type" :style="'background-color: ' + known.data.color">
|
<span class="type" :style="'background-color: ' + known.data.color">
|
||||||
@@ -63,6 +66,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<div id="connect-known-list-import">
|
||||||
|
Tip: You can
|
||||||
|
<a href="javascript:;" @click="importHosts">import</a> and
|
||||||
|
<a href="javascript:;" @click="exportHosts">export</a>
|
||||||
|
known remotes from and to a file.
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -78,6 +88,14 @@ export default {
|
|||||||
launcherBuilder: {
|
launcherBuilder: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => []
|
default: () => []
|
||||||
|
},
|
||||||
|
knownsExport: {
|
||||||
|
type: Function,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
knownsImport: {
|
||||||
|
type: Function,
|
||||||
|
default: () => []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
@@ -159,6 +177,86 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.$emit("clear-session", uid);
|
this.$emit("clear-session", uid);
|
||||||
|
},
|
||||||
|
exportHosts() {
|
||||||
|
let el = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const dataStr = JSON.stringify(this.knownsExport());
|
||||||
|
|
||||||
|
el = document.createElement("a");
|
||||||
|
el.setAttribute(
|
||||||
|
"href",
|
||||||
|
"data:text/plain;charset=utf-8," + btoa(dataStr)
|
||||||
|
);
|
||||||
|
el.setAttribute("target", "_blank");
|
||||||
|
el.setAttribute("download", "sshwifty.known-remotes.txt");
|
||||||
|
el.setAttribute(
|
||||||
|
"style",
|
||||||
|
"overflow: hidden; opacity: 0; width: 1px; height: 1px; top: -1px;" +
|
||||||
|
"left: -1px; position: absolute;"
|
||||||
|
);
|
||||||
|
|
||||||
|
document.body.appendChild(el);
|
||||||
|
|
||||||
|
el.click();
|
||||||
|
} catch (e) {
|
||||||
|
alert("Unable to export known remotes: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(el);
|
||||||
|
},
|
||||||
|
importHosts() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
let el = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
el = document.createElement("input");
|
||||||
|
el.setAttribute("type", "file");
|
||||||
|
el.setAttribute(
|
||||||
|
"style",
|
||||||
|
"overflow: hidden; opacity: 0; width: 1px; height: 1px; top: -1px;" +
|
||||||
|
"left: -1px; position: absolute;"
|
||||||
|
);
|
||||||
|
el.addEventListener("change", ev => {
|
||||||
|
const t = ev.target;
|
||||||
|
|
||||||
|
if (t.files.length <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.disabled = "disabled";
|
||||||
|
|
||||||
|
let r = new FileReader();
|
||||||
|
|
||||||
|
r.onload = () => {
|
||||||
|
try {
|
||||||
|
self.knownsImport(JSON.parse(atob(r.result)));
|
||||||
|
} catch (e) {
|
||||||
|
alert("Unable to import known remotes due to error: " + e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
r.readAsText(t.files[0], "utf-8");
|
||||||
|
});
|
||||||
|
|
||||||
|
document.body.appendChild(el);
|
||||||
|
|
||||||
|
el.click();
|
||||||
|
} catch (e) {
|
||||||
|
alert("Unable to load known remotes data due to error: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.removeChild(el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,12 +23,8 @@
|
|||||||
New remote
|
New remote
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li
|
<li :class="{ active: tab === 'known' }" @click="switchTab('known')">
|
||||||
:class="{ active: tab === 'known', disabled: knownsLength <= 0 }"
|
Known remotes <span class="label">{{ knownsLength }}</span>
|
||||||
@click="knownsLength > 0 && switchTab('known')"
|
|
||||||
>
|
|
||||||
Known remotes
|
|
||||||
<span v-if="knownsLength > 0" class="label">{{ knownsLength }}</span>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</template>
|
</template>
|
||||||
@@ -47,15 +43,6 @@ export default {
|
|||||||
default: 0
|
default: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
knownsLength(newVal) {
|
|
||||||
if (newVal > 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.switchTab("new");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
switchTab(to) {
|
switchTab(to) {
|
||||||
this.$emit("switch", to);
|
this.$emit("switch", to);
|
||||||
|
|||||||
Reference in New Issue
Block a user