Small improvements:

- Switch to CodeMirror
- Switch to Parcel Bundler
- Fix synchronisation bug
- Update dependencies
This commit is contained in:
Fabian Stamm
2020-11-24 21:59:32 +01:00
parent e873ae0396
commit 86ae6acc92
32 changed files with 5232 additions and 6877 deletions

View File

@ -1,10 +1,8 @@
import { h } from "preact"
import { h } from "preact";
import { Page } from "../../../page";
import Notes, { VaultList } from "../../../notes";
import "./vaults.scss"
import Lock from "feather-icons/dist/icons/lock.svg";
import Unlock from "feather-icons/dist/icons/unlock.svg";
import Settings from "feather-icons/dist/icons/settings.svg"
import "./vaults.scss";
import { Lock, Unlock, Settings } from "preact-feather";
import Navigation from "../../../navigation";
import { InputModal } from "../../modals/InputModal";
import { YesNoModal } from "../../modals/YesNoModal";
@ -18,7 +16,14 @@ export interface VaultsProps {
onSelected?: (vaultid: string) => void;
}
export default class VaultsPage extends Page<VaultsProps, { vaults: VaultList, modal: JSX.Element | undefined, context: JSX.Element | undefined }> {
export default class VaultsPage extends Page<
VaultsProps,
{
vaults: VaultList;
modal: h.JSX.Element | undefined;
context: h.JSX.Element | undefined;
}
> {
constructor(props: VaultsProps) {
super(props);
this.state = { vaults: [], modal: undefined, context: undefined };
@ -26,15 +31,14 @@ export default class VaultsPage extends Page<VaultsProps, { vaults: VaultList, m
}
updateVaults(s?: boolean) {
if (s)
return;
return new Promise(yes => {
Notes.getVaults().then(vaults => this.setState({ vaults }, yes))
})
if (s) return;
return new Promise((yes) => {
Notes.getVaults().then((vaults) => this.setState({ vaults }, yes));
});
}
componentWillMount() {
this.updateVaults()
this.updateVaults();
Notes.syncObservable.subscribe(this.updateVaults);
}
@ -42,15 +46,19 @@ export default class VaultsPage extends Page<VaultsProps, { vaults: VaultList, m
Notes.syncObservable.unsubscribe(this.updateVaults);
}
async getKey(vault: { name: string, id: string }, permanent = true) {
let inp_mod = new InputModal("Enter password for " + vault.name, "Password", "password");
async getKey(vault: { name: string; id: string }, permanent = true) {
let inp_mod = new InputModal(
"Enter password for " + vault.name,
"Password",
"password"
);
let key = undefined;
while (true) {
// inp_mod.show();
let value = await inp_mod.getResult(false);
if (value === null) {
console.log("Value is null")
inp_mod.close()
console.log("Value is null");
inp_mod.close();
return false;
} else {
key = Notes.passwordToKey(value);
@ -58,11 +66,11 @@ export default class VaultsPage extends Page<VaultsProps, { vaults: VaultList, m
await Notes.getVault(vault.id, key);
break;
} catch (err) {
Notifications.sendError("Invalid password!")
Notifications.sendError("Invalid password!");
}
}
}
inp_mod.close()
inp_mod.close();
let perm = false;
if (permanent) {
@ -79,27 +87,24 @@ export default class VaultsPage extends Page<VaultsProps, { vaults: VaultList, m
return true;
}
async openVault(vault: { name: string, encrypted: boolean, id: string }) {
async openVault(vault: { name: string; encrypted: boolean; id: string }) {
const action = () => {
if (this.props.selectVault) {
this.props.onSelected(vault.id);
} else {
Navigation.setPage("/vault", { id: vault.id })
Navigation.setPage("/vault", { id: vault.id });
}
}
};
if (vault.encrypted) {
let key = Notes.getVaultKey(vault.id);
if (key)
action()
if (key) action();
else {
if (await this.getKey(vault))
action();
if (await this.getKey(vault)) action();
}
} else {
action()
action();
}
}
async addButtonClick() {
@ -113,122 +118,176 @@ export default class VaultsPage extends Page<VaultsProps, { vaults: VaultList, m
let password;
if (encrypted) {
let password_modal = new InputModal("Enter new password", "Password", "password");
let password_modal = new InputModal(
"Enter new password",
"Password",
"password"
);
password = await password_modal.getResult();
if (password === null) return;
}
let key;
if (password) {
key = Notes.passwordToKey(password)
key = Notes.passwordToKey(password);
}
await Notes.createVault(name, key)
await Notes.createVault(name, key);
this.updateVaults();
}
onContext(evt: MouseEvent, vault: { name: string, encrypted: boolean, id: string }) {
onContext(
evt: MouseEvent,
vault: { name: string; encrypted: boolean; id: string }
) {
evt.preventDefault();
evt.stopPropagation();
const close = () => {
document.documentElement.removeEventListener("click", close);
this.setState({ context: undefined });
}
};
document.documentElement.addEventListener("click", close);
let deleteb = <button class="btn" onClick={async () => {
let delete_modal = new YesNoModal("Delete Vault? Cannot be undone!");
let result = await delete_modal.getResult();
if (result) {
Notes.deleteVault(vault.id).then(() => {
this.updateVaults();
}).catch(err => {
Notifications.sendError("Error deleting vault!")
console.error(err);
})
}
}}>
delete
</button>;
let deleteb = (
<button
class="btn"
onClick={async () => {
let delete_modal = new YesNoModal(
"Delete Vault? Cannot be undone!"
);
let result = await delete_modal.getResult();
if (result) {
Notes.deleteVault(vault.id)
.then(() => {
this.updateVaults();
})
.catch((err) => {
Notifications.sendError("Error deleting vault!");
console.error(err);
});
}
}}
>
delete
</button>
);
let delete_key;
if (Notes.getVaultKey(vault.id)) {
delete_key = <button class="btn" onClick={() => {
Notes.forgetVaultKey(vault.id);
Notifications.sendSuccess("Forgot password!")
}}>
forget password
</button>;
delete_key = (
<button
class="btn"
onClick={() => {
Notes.forgetVaultKey(vault.id);
Notifications.sendSuccess("Forgot password!");
}}
>
forget password
</button>
);
}
let exportb = <button class="btn" onClick={async () => {
let key: Uint8Array;
if (vault.encrypted) {
await this.getKey(vault, false)
key = Notes.getVaultKey(vault.id);
}
let note_vault = await Notes.getVault(vault.id, key);
let base_notes = await note_vault.getAllNotes();
let notes = await Promise.all(base_notes.map(e => {
return note_vault.getNote(e._id);
}));
let result =
{
version: 1,
notes: notes.map(e => {
return {
content: e.__value,
time: e.time
let exportb = (
<button
class="btn"
onClick={async () => {
let key: Uint8Array;
if (vault.encrypted) {
await this.getKey(vault, false);
key = Notes.getVaultKey(vault.id);
}
})
}
let note_vault = await Notes.getVault(vault.id, key);
let base_notes = await note_vault.getAllNotes();
let notes = await Promise.all(
base_notes.map((e) => {
return note_vault.getNote(e._id);
})
);
var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(result, undefined, 3));
var downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute("download", "notes_export_" + vault.name + ".json");
document.body.appendChild(downloadAnchorNode); // required for firefox
downloadAnchorNode.click();
downloadAnchorNode.remove();
}}>
export
</button>;
let result = {
version: 1,
notes: notes.map((e) => {
return {
content: e.__value,
time: e.time,
};
}),
};
let context = <ContextMenu event={evt} >
{deleteb}
{delete_key}
{exportb}
</ContextMenu>
var dataStr =
"data:text/json;charset=utf-8," +
encodeURIComponent(JSON.stringify(result, undefined, 3));
var downloadAnchorNode = document.createElement("a");
downloadAnchorNode.setAttribute("href", dataStr);
downloadAnchorNode.setAttribute(
"download",
"notes_export_" + vault.name + ".json"
);
document.body.appendChild(downloadAnchorNode); // required for firefox
downloadAnchorNode.click();
downloadAnchorNode.remove();
}}
>
export
</button>
);
let context = (
<ContextMenu event={evt}>
{deleteb}
{delete_key}
{exportb}
</ContextMenu>
);
this.setState({ context });
return false;
}
render() {
let elms = this.state.vaults.map(vault => {
return <li class="vaults_vault" onClick={() => this.openVault(vault)} onContextMenu={(evt) => this.onContext(evt, vault)}>
{vault.encrypted ? <Lock height={undefined} width={undefined} /> : <Unlock height={undefined} width={undefined} />}
<span>
{vault.name}
</span>
</li>
})
let elms = this.state.vaults.map((vault) => {
return (
<li
class="vaults_vault"
onClick={() => this.openVault(vault)}
onContextMenu={(evt) => this.onContext(evt, vault)}
>
{vault.encrypted ? (
<Lock height={undefined} width={undefined} />
) : (
<Unlock height={undefined} width={undefined} />
)}
<span>{vault.name}</span>
</li>
);
});
return <div style={{ marginTop: "-12px", paddingTop: "12px" }} >
{/* {this.state.modal} */}
{this.state.context}
<header class="header">
<span></span>
<h3 style="display:inline" onClick={() => Navigation.setPage("/")}>{this.props.selectVault ? "Select Vault for share" : "Your vaults:"}</h3>
<a class="header-icon-button" onClick={() => Navigation.setPage("/settings")}><Settings height={undefined} width={undefined} /></a>
</header>
<AddButton onClick={() => this.addButtonClick()} />
<div class="container">
<ul class="list list-divider list-clickable">
{elms}
</ul>
return (
<div style={{ marginTop: "-12px", paddingTop: "12px" }}>
{/* {this.state.modal} */}
{this.state.context}
<header class="header">
<span></span>
<h3
style="display:inline"
onClick={() => Navigation.setPage("/")}
>
{this.props.selectVault
? "Select Vault for share"
: "Your vaults:"}
</h3>
<a
class="header-icon-button"
onClick={() => Navigation.setPage("/settings")}
>
<Settings height={undefined} width={undefined} />
</a>
</header>
<AddButton onClick={() => this.addButtonClick()} />
<div class="container">
<ul class="list list-divider list-clickable">{elms}</ul>
</div>
</div>
</div>
);
}
}
}