Allowing "Known remotes" to be import and exported

This commit is contained in:
NI
2019-12-30 18:44:01 +08:00
parent edc6aeab92
commit e75ebed269
6 changed files with 221 additions and 37 deletions

View File

@@ -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();
}
} }

View File

@@ -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);

View File

@@ -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: () => []

View File

@@ -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 {

View File

@@ -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);
} }
} }
}; };

View File

@@ -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);