Implement big text view and preliminary i18n

This commit is contained in:
aet 2021-11-06 21:49:54 -04:00
parent d2ae4be194
commit 7ee6990be1
22 changed files with 624 additions and 263 deletions

View File

@ -8,6 +8,7 @@
"build:docs": "typedoc --out docs src/index.ts --excludePrivate"
},
"dependencies": {
"buffer": "^6.0.3",
"tiny-invariant": "1.2.0",
"tslib": "2.3.1"
},

View File

@ -14,11 +14,6 @@ function splitPath(path: string) {
export class FileSystem implements IFileSystem {
constructor(private handle: FileSystemDirectoryHandle) {}
static async create() {
const handle = await showDirectoryPicker()
return new FileSystem(handle)
}
private async getDirectoryHandle(segments: string[]) {
if (!segments.length || (segments.length === 1 && !segments[0])) {
return this.handle

View File

@ -0,0 +1,53 @@
import { Buffer } from "buffer"
import type { IAdapter, IFileSystem } from "./index"
export class FileSystem implements IFileSystem {
private paths = new Set<string>()
private pathMap = new Map<string, File>()
constructor(list: FileList) {
for (const file of list) {
this.pathMap.set(file.webkitRelativePath, file)
this.paths.add(file.webkitRelativePath)
}
}
async readFile(path: string) {
return this.pathMap.get(path)!.text()
}
async exists(path: string): Promise<boolean> {
return this.pathMap.has(path)
}
async readBuffer(path: string): Promise<Buffer> {
const arrayBuffer = await this.pathMap.get(path)!.arrayBuffer()
return Buffer.from(arrayBuffer)
}
// eslint-disable-next-line class-methods-use-this
async writeFile(path: string, data: string): Promise<void> {
throw new Error("fs.writeFile is not supported with webkitdirectory")
}
async readdir(path: string): Promise<string[]> {
const paths = [...this.paths]
return paths
.filter(_ => _.startsWith(`${path}/`))
.map(_ => _.slice(path.length + 1))
.map(_ => _.split("/")[0])
}
async isDirectory(path: string) {
const paths = [...this.paths]
return paths.some(_ => _.startsWith(`${path}/`)) && !paths.includes(path)
}
}
/**
* Default Browser adapter.
*/
export const getBrowserAdapter = (list: FileList): IAdapter => ({
fs: new FileSystem(list),
subtle: crypto.subtle,
})

View File

@ -3,3 +3,4 @@ node_modules
dist
bundle
*.local
*.yml.d.ts

View File

@ -8,10 +8,7 @@ const args = process.argv.slice(2)
build({
bundle: true,
define: {},
entryPoints: [
"./src/electron/index.ts",
// "./src/electron/preload.ts"
],
entryPoints: ["./src/electron/index.ts"],
outdir: "./dist/main",
external: builtinModules.concat("electron"),
target: ["chrome90"],

263
packages/web/logo.svg Normal file
View File

@ -0,0 +1,263 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 128 128"
version="1.0"
id="svg11300"
height="128"
width="128"
>
<style>
.card-rect {
/* fill: #2ec27e; */
fill: #496ccf;
}
.barcode-1,
.barcode-2,
.barcode-3 {
/* stroke: #26a269; */
stroke: #7b95e1;z
}
#path1138 {
fill: #7b95e1;z
}
.barcode-1 {
stroke-width: 1.87082875;
}
.barcode-2 {
stroke-width: 3.7416575;
}
.barcode-3 {
stroke-width: 5.61248589;
}
</style>
<title id="title4162">Adwaita Icon Template</title>
<defs id="defs3">
<linearGradient id="linearGradient1296">
<stop id="stop1292" offset="0" style="stop-color: #77767b; stop-opacity: 1" />
<stop
style="stop-color: #c0bfbc; stop-opacity: 1"
offset="0.17589436"
id="stop1300"
/>
<stop
id="stop1302"
offset="0.4092612"
style="stop-color: #77767b; stop-opacity: 1"
/>
<stop id="stop1294" offset="1" style="stop-color: #3d3846; stop-opacity: 1" />
</linearGradient>
<linearGradient id="linearGradient969">
<stop style="stop-color: #f6f5f4; stop-opacity: 1" offset="0" id="stop963" />
<stop
id="stop965"
offset="0.25731823"
style="stop-color: #ffffff; stop-opacity: 1"
/>
<stop
style="stop-color: #c0bfbc; stop-opacity: 1"
offset="0.5999999"
id="stop1085"
/>
<stop
id="stop1087"
offset="0.70312482"
style="stop-color: #f6f5f4; stop-opacity: 1"
/>
<stop style="stop-color: #f6f5f4; stop-opacity: 1" offset="1" id="stop967" />
</linearGradient>
<linearGradient id="linearGradient1040">
<stop style="stop-color: #c0bfbc; stop-opacity: 1" offset="0" id="stop1036" />
<stop style="stop-color: #f6f5f4; stop-opacity: 1" offset="1" id="stop1038" />
</linearGradient>
<linearGradient
y2="249.87819"
x2="67.121834"
y1="238.30762"
x1="78.692398"
gradientTransform="translate(55.100502, 0.07106726)"
gradientUnits="userSpaceOnUse"
id="linearGradient1986"
xlink:href="#linearGradient969"
/>
<linearGradient
y2="70.300697"
x2="85.886963"
y1="67.679771"
x1="88.507896"
gradientTransform="translate(55.769701, 171.28412)"
gradientUnits="userSpaceOnUse"
id="linearGradient1988"
xlink:href="#linearGradient1040"
/>
<linearGradient
gradientUnits="userSpaceOnUse"
y2="268"
x2="198"
y1="268"
x1="142"
id="linearGradient1039"
xlink:href="#linearGradient1296"
/>
</defs>
<metadata id="metadata4">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:creator>
<cc:Agent>
<dc:title>GNOME Design Team</dc:title>
</cc:Agent>
</dc:creator>
<dc:source />
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
<dc:title>Adwaita Icon Template</dc:title>
<dc:subject>
<rdf:Bag />
</dc:subject>
<dc:date />
<dc:rights>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:rights>
<dc:publisher>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:publisher>
<dc:identifier />
<dc:relation />
<dc:language />
<dc:coverage />
<dc:description />
<dc:contributor>
<cc:Agent>
<dc:title />
</cc:Agent>
</dc:contributor>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g transform="translate(0, -172)" id="layer1">
<g id="layer9">
<rect
class="card-rect"
id="rect1027"
width="112"
height="63.999977"
x="8"
y="224"
rx="8"
ry="8"
/>
<g id="g1256" transform="matrix(1,0,0,1.1428571,-4.8522949e-8,-22.857143)">
<path class="barcode-1" d="m 27,230 v 14" id="path1164" />
<path class="barcode-2" d="m 32,230 v 14" id="path1166" />
<path class="barcode-1" d="m 37,230 v 14" id="path1168" />
<path class="barcode-1" d="m 41,230 v 14" id="path1170" />
<path class="barcode-2" d="m 46,230 v 14" id="path1172" />
<path class="barcode-2" d="m 56,230 v 14" id="path1174" />
<path class="barcode-1" d="m 51,230 v 14" id="path1176" />
<path class="barcode-3" d="m 63,230 v 14" id="path1178" />
<path class="barcode-1" d="m 69,230 v 14" id="path1180" />
<path class="barcode-1" d="m 73,230 v 14" id="path1182" />
<path class="barcode-1" d="m 77,230 v 14" id="path1184" />
<path class="barcode-2" d="m 82,230 v 14" id="path1186" />
<path class="barcode-1" d="m 87,230 v 14" id="path1188" />
<path class="barcode-1" d="m 99,230 v 14" id="path1190" />
<path class="barcode-3" d="m 93,230 v 14" id="path1192" />
<path class="barcode-1" d="m 103,230 v 14" id="path1194" />
<path class="barcode-1" d="m 107,230 v 14" id="path1196" />
</g>
<g
style="display: inline; fill: #f8faff; enable-background: new"
id="g1130"
transform="translate(-4.8522949e-8,12)"
>
<path
d="m 22.21582,254 1.197265,5.06836 -3.90039,-3.2793 -1.453125,2.5918 5.009765,1.6582 -5.042968,1.58985 1.433593,2.64062 3.955078,-3.30469 L 22.21582,266 h 3.410156 l -1.101562,-4.95898 3.833984,3.31445 1.476562,-2.61914 -4.978515,-1.68555 5.117187,-1.42578 -1.453125,-2.61914 -4.033203,3.08398 L 25.624023,254 Z"
id="path1940"
/>
<path
id="path1056"
d="m 38.21582,254 1.197265,5.06836 -3.90039,-3.2793 -1.453125,2.5918 5.009765,1.6582 -5.042968,1.58985 1.433593,2.64062 3.955078,-3.30469 L 38.21582,266 h 3.410156 l -1.101562,-4.95898 3.833984,3.31445 1.476562,-2.61914 -4.978515,-1.68555 5.117187,-1.42578 -1.453125,-2.61914 -4.033203,3.08398 L 41.624023,254 Z"
/>
<path
d="m 54.21582,254 1.197265,5.06836 -3.90039,-3.2793 -1.453125,2.5918 5.009765,1.6582 -5.042968,1.58985 1.433593,2.64062 3.955078,-3.30469 L 54.21582,266 h 3.410156 l -1.101562,-4.95898 3.833984,3.31445 1.476562,-2.61914 -4.978515,-1.68555 5.117187,-1.42578 -1.453125,-2.61914 -4.033203,3.08398 L 57.624023,254 Z"
id="path1062"
/>
<path
id="path1068"
d="m 70.21582,254 1.197265,5.06836 -3.90039,-3.2793 -1.453125,2.5918 5.009765,1.6582 -5.042968,1.58985 1.433593,2.64062 3.955078,-3.30469 L 70.21582,266 h 3.410156 l -1.101562,-4.95898 3.833984,3.31445 1.476562,-2.61914 -4.978515,-1.68555 5.117187,-1.42578 -1.453125,-2.61914 -4.033203,3.08398 L 73.624023,254 Z"
/>
<path
d="m 86.21582,254 1.197265,5.06836 -3.90039,-3.2793 -1.453125,2.5918 5.009765,1.6582 -5.042968,1.58985 1.433593,2.64062 3.955078,-3.30469 L 86.21582,266 h 3.410156 l -1.101562,-4.95898 3.833984,3.31445 1.476562,-2.61914 -4.978515,-1.68555 5.117187,-1.42578 -1.453125,-2.61914 -4.033203,3.08398 L 89.624023,254 Z"
id="path1074"
/>
<path
id="path1080"
d="m 102.21582,254 1.19726,5.06836 -3.900385,-3.2793 -1.453125,2.5918 5.00976,1.6582 -5.042963,1.58985 1.433593,2.64062 3.95508,-3.30469 L 102.21582,266 h 3.41016 l -1.10157,-4.95898 3.83399,3.31445 1.47656,-2.61914 -4.97851,-1.68555 5.11718,-1.42578 -1.45312,-2.61914 -4.03321,3.08398 L 105.62402,254 Z"
/>
</g>
<rect
ry="7.9999995"
rx="8"
y="200"
x="8"
height="40"
width="112"
id="rect954"
class="card-rect"
/>
<rect y="214" x="8" height="18" width="112" id="rect961" style="fill: #241f31" />
<path id="path1138" d="m 22,242 -7.2,6 7.2,6 z" />
</g>
<g id="g959-3" transform="rotate(-180,107.5,242)">
<path
style="fill: url(#linearGradient1039)"
d="m 170,296 a 28,28 0 0 1 -28,-28 28,28 0 0 1 28,-28 28,28 0 0 1 28,28 28,28 0 0 1 -28,28 z m 0.0312,-12 a 6.0312505,6.0000005 0 0 0 6.03125,-6 6.0312505,6.0000005 0 0 0 -6.03125,-6 6.0312505,6.0000005 0 0 0 -6.03125,6 6.0312505,6.0000005 0 0 0 6.03125,6 z"
id="path947-0"
/>
<g
transform="matrix(0.70710678,-0.70710678,-0.70710678,-0.70710678,243.95332,484.3158)"
id="g955-3"
>
<path
id="path1990"
d="m 125.41422,214.44366 -16.97055,16.97056 8.36742,8.36743 3.65338,-3.41768 4.24264,4.24264 h 2.82843 v 2.82843 l 2.12132,2.12132 h 4.24264 v 4.24264 h 2.82843 v 2.82842 h 5.65685 v 5.65686 h 2.82843 v 2.82843 h 12.72792 l 4.94974,-4.94976 v -4.24264 z"
style="fill: #77767b"
/>
<path
style="fill: url(#linearGradient1986)"
d="M 124,213.02944 107.02945,230 l 8.36742,8.36743 3.65338,-3.41768 4.24264,4.24264 h 2.82843 v 2.82843 l 2.12132,2.12132 h 4.24264 v 4.24264 h 2.82843 v 2.82842 h 5.65685 v 5.65686 h 2.82843 v 2.82843 h 12.72792 l 4.94974,-4.94976 v -4.24264 z"
id="path951-1"
/>
<path
style="fill: url(#linearGradient1988)"
d="m 125.74823,221.26459 c -1.79388,0.002 -2.67811,2.18243 -1.39257,3.43359 l 33.58547,33.5861 2.82844,-2.82843 -33.58579,-33.58579 c -0.37702,-0.38755 -0.89487,-0.60597 -1.43555,-0.60547 z"
id="path953-2"
/>
</g>
<path
id="path957-8"
d="m 170,298 a 28,28 0 0 0 28,-28 28,28 0 0 0 -28,-28 28,28 0 0 0 -28,28 28,28 0 0 0 28,28 z m -0.0312,-12 a 6.0312505,6.0000005 0 0 1 -6.03125,-6 6.0312505,6.0000005 0 0 1 6.03125,-6 6.0312505,6.0000005 0 0 1 6.03125,6 6.0312505,6.0000005 0 0 1 -6.03125,6 z"
style="fill: #f6f5f4"
/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,6 +1,6 @@
{
"name": "opvault-web",
"version": "0.0.0",
"version": "1.0.0",
"main": "dist/main/index.js",
"author": "proteria",
"license": "GPL-3.0-only",
@ -9,13 +9,14 @@
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"start": "NODE_ENV=development electron --enable-transparent-visuals --disable-gpu ./dist/main/index.js",
"start": "./esbuild.js && NODE_ENV=development electron --enable-transparent-visuals --disable-gpu ./dist/main/index.js",
"bundle": "./scripts/build.sh"
},
"devDependencies": {
"@emotion/css": "^11.5.0",
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@rollup/plugin-yaml": "^3.1.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@vitejs/plugin-react": "^1.0.0",
@ -23,6 +24,7 @@
"electron": "^15.2.0",
"electron-builder": "^22.13.1",
"esbuild": "^0.13.6",
"js-yaml": "^4.1.0",
"opvault.js": "*",
"path-browserify": "^1.0.1",
"react": "^17.0.0",
@ -38,14 +40,19 @@
"files": [
"**/*"
],
"icon": "dist/512x512.png",
"directories": {
"output": "bundle",
"app": "dist"
"app": "dist",
"buildResources": "build"
},
"linux": {
"executableName": "opvault",
"icon": "1p.png",
"category": "Utility"
"category": "Utility",
"icon": "512x512.png",
"target": [
"AppImage"
]
}
}
}

View File

@ -0,0 +1,21 @@
#!/usr/bin/env node
const fs = require("fs")
const { resolve } = require("path")
const { load } = require("js-yaml")
const ymlPath = resolve(__dirname, "../src/i18n/texts.yml")
const json = load(fs.readFileSync(ymlPath, "utf-8"))
const dtsPath = ymlPath + ".d.ts"
fs.writeFileSync(
dtsPath,
`type Translation = Record<string, string>;
declare const exportee: {
${Object.keys(json)
.map(x => `${x}: Translation;`)
.join("\n ")}
};
export default exportee;
`
)

View File

@ -1,5 +1,5 @@
#!/bin/sh
yarn build
npx vite build
NODE_ENV=production ./esbuild.js
./scripts/build-package-json.js
./node_modules/.bin/electron-builder build

View File

@ -0,0 +1,51 @@
import styled from "@emotion/styled"
import { memo, useEffect } from "react"
const Container = styled.div`
background: rgba(255, 255, 255, 0.6);
backdrop-filter: blur(4px);
border-radius: 20px;
font-family: var(--monospace);
letter-spacing: 2px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 8em;
text-align: center;
padding: 20px 25px;
word-break: break-word;
@media (prefers-color-scheme: dark) {
background: rgba(0, 0, 0, 0.6);
}
`
const Letter = styled.span`
&:nth-of-type(even) {
opacity: 0.8;
}
`
interface BigTextViewProps {
onClose(): void
children: string
}
export const BigTextView = memo<BigTextViewProps>(({ onClose, children }) => {
useEffect(() => {
const fn = (e: KeyboardEvent) => {
if (e.code === "Escape") {
onClose()
}
}
document.addEventListener("keydown", fn)
return () => document.removeEventListener("keydown", fn)
}, [onClose])
return (
<Container>
{children.split("").map((letter, i) => (
<Letter key={i}>{letter}</Letter>
))}
</Container>
)
})

View File

@ -1,5 +1,6 @@
import styled from "@emotion/styled"
import type { Item } from "opvault.js"
import { useTranslate } from "../i18n"
const Container = styled.div`
text-align: center;
@ -8,9 +9,16 @@ const Container = styled.div`
opacity: 0.5;
`
export const ItemDates: React.FC<{ item: Item }> = ({ item }) => (
<Container>
<div>Last Updated: {new Date(item.updatedAt).toLocaleString()}</div>
<div>Created: {new Date(item.createdAt).toLocaleString()}</div>
</Container>
)
export const ItemDates: React.FC<{ item: Item }> = ({ item }) => {
const t = useTranslate()
return (
<Container>
<div>
{t.label_last_updated}: {new Date(item.updatedAt).toLocaleString()}
</div>
<div>
{t.label_created_at}: {new Date(item.createdAt).toLocaleString()}
</div>
</Container>
)
}

View File

@ -3,6 +3,7 @@ import type { ItemSection, ItemField } from "opvault.js"
import { FieldType } from "opvault.js"
import { useCallback, useMemo, useState } from "react"
import { parseMonthYear } from "../utils"
import { BigTextView } from "./BigTextView"
import { ErrorBoundary } from "./ErrorBoundary"
import { useItemFieldContextMenu } from "./ItemFieldContextMenu"
@ -12,11 +13,19 @@ const Password: React.FC<{
field: ItemSection.Concealed
}> = ({ field }) => {
const [show, setShow] = useState(false)
const [bigText, showBigText] = useState(false)
const { onRightClick, ContextMenuContainer, Item } = useItemFieldContextMenu()
const onToggle = useCallback(() => setShow(x => !x), [])
const onCopy = useCallback(() => {
navigator.clipboard.writeText(field.v)
}, [field.v])
const onOpenBigText = useCallback(() => {
showBigText(true)
}, [])
const onCloseBigText = useCallback(() => {
showBigText(false)
}, [])
return (
<>
@ -30,9 +39,11 @@ const Password: React.FC<{
>
{show ? field.v : "·".repeat(10)}
</Container>
{bigText && <BigTextView onClose={onCloseBigText}>{field.v}</BigTextView>}
<ContextMenuContainer>
<Item onClick={onCopy}>Copier</Item>
<Item onClick={onToggle}>{show ? "Cacher" : "Afficher"}</Item>
{!bigText && <Item onClick={onOpenBigText}>Afficher en gros caractères</Item>}
</ContextMenuContainer>
</>
)
@ -52,6 +63,22 @@ const DateView: React.FC<{ field: ItemSection.Date }> = ({ field }) => {
return <Container>{date.toLocaleDateString()}</Container>
}
const TextView: React.FC<{ value: string }> = ({ value }) => {
const { onRightClick, ContextMenuContainer, Item } = useItemFieldContextMenu()
const onCopy = useCallback(() => {
navigator.clipboard.writeText(value)
}, [value])
return (
<>
<Container onContextMenu={onRightClick}>{value}</Container>
<ContextMenuContainer>
<Item onClick={onCopy}>Copier</Item>
</ContextMenuContainer>
</>
)
}
export const ItemFieldValue: React.FC<{
field: ItemSection.Any
}> = ({ field }) => {
@ -80,7 +107,7 @@ export const ItemFieldValue: React.FC<{
return (
<ErrorBoundary>
<Container>{field.v}</Container>
<TextView value={field.v} />
</ErrorBoundary>
)
}

View File

@ -1,8 +1,11 @@
import { useCallback } from "react"
import { useTranslate } from "../i18n"
export const VaultPicker: React.FC<{
setHandle(handle: FileSystemDirectoryHandle): void
}> = ({ setHandle }) => {
const t = useTranslate()
const onClick = useCallback(async () => {
try {
const handle = await showDirectoryPicker()
@ -15,5 +18,5 @@ export const VaultPicker: React.FC<{
}
}, [setHandle])
return <button onClick={onClick}>Pick a vault here.</button>
return <button onClick={onClick}>{t.label_choose_a_vault}</button>
}

View File

@ -1,6 +1,6 @@
// @ts-check
// Modules to control application life and create native browser window
// import { join } from "path"
import { join } from "path"
import { app, BrowserWindow, Menu } from "electron"
function createWindow() {
@ -10,6 +10,7 @@ function createWindow() {
height: 650,
// frame: false,
// transparent: true,
icon: join(__dirname, "../512x512.png"),
webPreferences: {
contextIsolation: true,
// preload: join(__dirname, "preload.js"),

View File

@ -0,0 +1,73 @@
import { createContext, memo, useContext, useEffect, useMemo, useState } from "react"
import texts from "./texts.yml"
type Keys = keyof typeof texts
const ALLOWED = new Set(["en", "fr"])
const LOCALSTORAGE_KEY = "preferred-locale"
function getLocaleFromStorage() {
try {
const key = localStorage.getItem(LOCALSTORAGE_KEY)
if (key && ALLOWED.has(key)) {
return key
}
} catch {}
}
function getNavigatorLocale() {
if (typeof navigator !== "undefined") {
for (const lang of navigator.languages) {
if (ALLOWED.has(lang)) {
return lang
}
}
}
}
function getEnvLocale() {
return getLocaleFromStorage() ?? getNavigatorLocale() ?? "en"
}
const LocaleContext = createContext<{
locale: string
setLocale(locale: string): void
}>(undefined!)
export const useLocaleContext = () => useContext(LocaleContext)
export function useTranslate() {
const { locale } = useContext(LocaleContext)
const t = useMemo(
() =>
new Proxy(
{},
{
get(_, p: string) {
if (
process.env.NODE_ENV === "development" &&
!Object.prototype.hasOwnProperty.call(texts, p)
) {
throw new Error(`t.${p} does not exist.`)
}
return (texts as any)[p][locale]
},
}
) as {
[key in Keys]: string
},
[locale]
)
return t
}
export const LocaleContextProvider = memo(({ children }) => {
const [locale, setLocale] = useState(getEnvLocale)
useEffect(() => {
try {
localStorage.setItem(LOCALSTORAGE_KEY, locale)
} catch {}
}, [locale])
const value = useMemo(() => ({ locale, setLocale }), [locale])
return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>
})

View File

@ -0,0 +1,28 @@
# /* spellchecker: disable */
label_choose_a_vault:
en: Pick a vault here.
fr: Choisir un coffre ici.
label_no_vault_selected:
en: No vault is selected.
fr: Aucun coffre nest sélectionné.
label_last_updated:
en: Last Updated
fr: Dernière modification
label_created_at:
en: Created At
fr: Créé
noun_vault:
en: vault
fr: coffre
action_lock:
en: Lock
fr: Vérouiller
action_unlock:
en: Unlock
fr: Déverouiller

View File

@ -1,12 +1,15 @@
import React from "react"
import { render } from "react-dom"
import { App } from "./App"
import { LocaleContextProvider } from "./i18n"
import "./index.scss"
render(
<React.StrictMode>
{/* <TitleBar /> */}
<App />
<LocaleContextProvider>
<App />
</LocaleContextProvider>
</React.StrictMode>,
document.getElementById("root")
)

View File

@ -1,8 +1,8 @@
import styled from "@emotion/styled"
import { VaultPicker } from "../components/VaultPicker"
import { useTranslate } from "../i18n"
const Container = styled.div`
width: 800px;
padding: 100px;
text-align: center;
`
@ -12,9 +12,12 @@ const Info = styled.div`
export const PickOPVault: React.FC<{
setHandle(handle: FileSystemDirectoryHandle): void
}> = ({ setHandle }) => (
<Container>
<VaultPicker setHandle={setHandle} />
<Info>No vault is picked.</Info>
</Container>
)
}> = ({ setHandle }) => {
const t = useTranslate()
return (
<Container>
<VaultPicker setHandle={setHandle} />
<Info>{t.label_no_vault_selected}</Info>
</Container>
)
}

View File

@ -1,8 +1,9 @@
import type { OnePassword } from "opvault.js"
import styled from "@emotion/styled"
import { useCallback, useEffect, useState } from "react"
import { useTranslate } from "../i18n"
const Container = styled.div`
const Container = styled.form`
padding: 20px;
text-align: center;
`
@ -11,15 +12,21 @@ export const Unlock: React.FC<{
instance: OnePassword
onUnlock(profile: string, password: string): void
}> = ({ onUnlock, instance }) => {
const t = useTranslate()
const [profiles, setProfiles] = useState<string[]>(() => [])
const [profile, setProfile] = useState<string>()
const [password, setPassword] = useState("")
const unlock = useCallback(() => {
if (!profile) return
onUnlock(profile, password)
setPassword("")
}, [onUnlock, profile, password])
const unlock = useCallback(
(e: React.FormEvent) => {
e.preventDefault()
if (!profile) return
onUnlock(profile, password)
setPassword("")
},
[onUnlock, profile, password]
)
useEffect(() => {
instance.getProfileNames().then(profiles => {
@ -29,12 +36,12 @@ export const Unlock: React.FC<{
}, [instance])
return (
<Container>
<Container onSubmit={unlock}>
<div>
<select value={profile} onChange={e => setProfile(e.currentTarget.value)}>
{profiles.map(p => (
<option key={p} value={p}>
Vault: {p}
{t.noun_vault}: {p}
</option>
))}
</select>
@ -46,8 +53,8 @@ export const Unlock: React.FC<{
onChange={e => setPassword(e.currentTarget.value)}
/>
</div>
<button type="submit" disabled={!profile || !password} onClick={unlock}>
Unlock
<button type="submit" disabled={!profile || !password}>
{t.action_unlock}
</button>
</Container>
)

View File

@ -6,6 +6,7 @@ import { IoSearch } from "react-icons/io5"
import { ItemList } from "../components/ItemList"
import { ItemView } from "../components/Item"
import { reactIconClass } from "../components/CategoryIcon"
import { useTranslate } from "../i18n/index"
const Container = styled.div`
display: flex;
@ -54,6 +55,7 @@ export const VaultView: React.FC<{ vault: Vault; onLock(): void }> = ({
vault,
onLock,
}) => {
const t = useTranslate()
const [items, setItems] = useState<Item[]>(() => [])
const [item, setItem] = useState<Item>()
const [sortBy, setSortBy] = useState(SortBy.Name)
@ -99,7 +101,7 @@ export const VaultView: React.FC<{ vault: Vault; onLock(): void }> = ({
margin: "10px 10px",
}}
>
<button onClick={onLock}>Lock</button>
<button onClick={onLock}>{t.action_lock}</button>
</div>
<SearchContainer>
<SearchInput

View File

@ -1,10 +1,11 @@
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import yaml from "@rollup/plugin-yaml"
// https://vitejs.dev/config/
export default defineConfig({
base: "./",
plugins: [react()],
plugins: [react(), yaml()],
define: {
global: "globalThis",
"process.browser": "true",
@ -16,6 +17,7 @@ export default defineConfig({
resolve: {
alias: {
path: require.resolve("path-browserify"),
buffer: require.resolve("buffer"),
},
},
})

253
pnpm-lock.yaml generated
View File

@ -74,7 +74,7 @@ importers:
specifiers:
'@rollup/plugin-json': ^4.1.0
'@rollup/plugin-replace': ^3.0.0
build: ^0.1.4
buffer: ^6.0.3
prettier: ^2.4.1
rollup: ^2.58.0
rollup-plugin-ts: ^1.4.7
@ -82,12 +82,12 @@ importers:
tslib: 2.3.1
typedoc: ^0.22.7
dependencies:
buffer: 6.0.3
tiny-invariant: 1.2.0
tslib: 2.3.1
devDependencies:
'@rollup/plugin-json': 4.1.0_rollup@2.58.0
'@rollup/plugin-replace': 3.0.0_rollup@2.58.0
build: 0.1.4
prettier: 2.4.1
rollup: 2.58.0
rollup-plugin-ts: 1.4.7_rollup@2.58.0+typescript@4.4.3
@ -98,6 +98,7 @@ importers:
'@emotion/css': ^11.5.0
'@emotion/react': ^11.5.0
'@emotion/styled': ^11.3.0
'@rollup/plugin-yaml': ^3.1.0
'@types/react': ^17.0.0
'@types/react-dom': ^17.0.0
'@vitejs/plugin-react': ^1.0.0
@ -105,6 +106,7 @@ importers:
electron: ^15.2.0
electron-builder: ^22.13.1
esbuild: ^0.13.6
js-yaml: ^4.1.0
opvault.js: '*'
path-browserify: ^1.0.1
react: ^17.0.0
@ -117,6 +119,7 @@ importers:
'@emotion/css': 11.5.0
'@emotion/react': 11.5.0_0d9ae6029f9b6856f7d6fb45bd27ecc7
'@emotion/styled': 11.3.0_a18847030f5d66c91ccc2d367a906fbb
'@rollup/plugin-yaml': 3.1.0
'@types/react': 17.0.30
'@types/react-dom': 17.0.9
'@vitejs/plugin-react': 1.0.7
@ -124,6 +127,7 @@ importers:
electron: 15.2.0
electron-builder: 22.13.1
esbuild: 0.13.6
js-yaml: 4.1.0
opvault.js: link:../opvault.js
path-browserify: 1.0.1
react: 17.0.2
@ -133,6 +137,9 @@ importers:
typescript: 4.4.3
vite: 2.6.13_sass@1.43.4
packages/web/bundle/linux-unpacked/resources/app:
specifiers: {}
packages/web/dist:
specifiers: {}
@ -1362,14 +1369,6 @@ packages:
'@cspotcode/source-map-consumer': 0.8.0
dev: true
/@dabh/diagnostics/2.0.2:
resolution: {integrity: sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q==}
dependencies:
colorspace: 1.1.4
enabled: 2.0.0
kuler: 2.0.0
dev: true
/@develar/schema-utils/2.6.5:
resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==}
engines: {node: '>= 8.9.0'}
@ -1634,6 +1633,28 @@ packages:
rollup: 2.58.0
dev: true
/@rollup/plugin-yaml/3.1.0:
resolution: {integrity: sha512-61PsAXqN7YNYdg/nezK3NkqAu6e3Qu2wjHYW3r52Nx0aLi+rG7gkkIqtvxG8EtSqE2rra5CUcWBZj+v362qt9A==}
engines: {node: '>=10.0.0'}
peerDependencies:
rollup: ^1.20.0 || ^2.0.0
dependencies:
'@rollup/pluginutils': 3.1.0
js-yaml: 3.14.0
tosource: 1.0.0
dev: true
/@rollup/pluginutils/3.1.0:
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
engines: {node: '>= 8.0.0'}
peerDependencies:
rollup: ^1.20.0||^2.0.0
dependencies:
'@types/estree': 0.0.39
estree-walker: 1.0.1
picomatch: 2.3.0
dev: true
/@rollup/pluginutils/3.1.0_rollup@2.58.0:
resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==}
engines: {node: '>= 8.0.0'}
@ -2248,10 +2269,6 @@ packages:
resolution: {integrity: sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=}
dev: true
/async/3.2.2:
resolution: {integrity: sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g==}
dev: true
/at-least-node/1.0.0:
resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==}
engines: {node: '>= 4.0.0'}
@ -2313,7 +2330,6 @@ packages:
/base64-js/1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: true
/binary-extensions/2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
@ -2449,23 +2465,6 @@ packages:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: true
/build/0.1.4:
resolution: {integrity: sha1-cH/gJv/O3crL/c3zVur9pk8VEEY=}
engines: {node: '>v0.4.12'}
dependencies:
cssmin: 0.3.2
jsmin: 1.0.1
jxLoader: 0.1.1
moo-server: 1.3.0
promised-io: 0.3.6
timespan: 2.3.0
uglify-js: 1.3.5
walker: 1.0.8
winston: 3.3.3
wrench: 1.3.9
dev: true
/builder-util-runtime/8.8.1:
resolution: {integrity: sha512-xHxAzdsJmMV8m/N+INzYUKfyJASeKyKHnA1uGkY8Y8JKLI/c4BG+If+L0If2YETv96CiRASkvd02tIt2pvrchQ==}
@ -2665,37 +2664,11 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/color-string/1.6.0:
resolution: {integrity: sha512-c/hGS+kRWJutUBEngKKmk4iH3sD59MBkoxVapS/0wgpCz2u7XsNloxknyvBhzwEs1IbV36D9PwqLPJ2DTu3vMA==}
dependencies:
color-name: 1.1.4
simple-swizzle: 0.2.2
dev: true
/color/3.2.1:
resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==}
dependencies:
color-convert: 1.9.3
color-string: 1.6.0
dev: true
/colors/1.0.3:
resolution: {integrity: sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=}
engines: {node: '>=0.1.90'}
dev: true
/colors/1.4.0:
resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
engines: {node: '>=0.1.90'}
dev: true
/colorspace/1.1.4:
resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
dependencies:
color: 3.2.1
text-hex: 1.0.0
dev: true
/commander/2.9.0:
resolution: {integrity: sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=}
engines: {node: '>= 0.6.x'}
@ -2830,11 +2803,6 @@ packages:
engines: {node: '>=8'}
dev: true
/cssmin/0.3.2:
resolution: {integrity: sha1-3c5MVHtRCuDVlKjx+/iq+OLFwA0=}
hasBin: true
dev: true
/csstype/3.0.9:
resolution: {integrity: sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==}
dev: true
@ -3105,10 +3073,6 @@ packages:
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
dev: true
/enabled/2.0.0:
resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==}
dev: true
/encodeurl/1.0.2:
resolution: {integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=}
engines: {node: '>= 0.8'}
@ -3672,10 +3636,6 @@ packages:
pend: 1.2.0
dev: true
/fecha/4.2.1:
resolution: {integrity: sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==}
dev: true
/file-entry-cache/6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
engines: {node: ^10.12.0 || >=12.0.0}
@ -3739,10 +3699,6 @@ packages:
resolution: {integrity: sha512-XprP7lDrVT+kE2c2YlfiV+IfS9zxukiIOvNamPNsImNhXadSsQEbosItdL9bUQlCZXR13SvPk20BjWSWLA7m4A==}
dev: true
/fn.name/1.1.0:
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
dev: true
/fs-extra/10.0.0:
resolution: {integrity: sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==}
engines: {node: '>=12'}
@ -4066,7 +4022,6 @@ packages:
/ieee754/1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: true
/ignore/4.0.6:
resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==}
@ -4129,10 +4084,6 @@ packages:
resolution: {integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=}
dev: true
/is-arrayish/0.3.2:
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
dev: true
/is-bigint/1.0.2:
resolution: {integrity: sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==}
dev: true
@ -4271,11 +4222,6 @@ packages:
resolution: {integrity: sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==}
dev: true
/is-stream/2.0.1:
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
engines: {node: '>=8'}
dev: true
/is-string/1.0.6:
resolution: {integrity: sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==}
engines: {node: '>= 0.4'}
@ -4357,11 +4303,6 @@ packages:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true
/js-yaml/0.3.7:
resolution: {integrity: sha1-1znY7oZGHlSzVNan19HyrZoWf2I=}
engines: {node: '> 0.4.11'}
dev: true
/js-yaml/3.14.0:
resolution: {integrity: sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==}
hasBin: true
@ -4388,12 +4329,6 @@ packages:
hasBin: true
dev: true
/jsmin/1.0.1:
resolution: {integrity: sha1-570NzWSWw79IYyNb9GGj2YqjuYw=}
engines: {node: '>=0.1.93'}
hasBin: true
dev: true
/json-buffer/3.0.0:
resolution: {integrity: sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=}
dev: true
@ -4467,26 +4402,12 @@ packages:
resolution: {integrity: sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==}
dev: true
/jxLoader/0.1.1:
resolution: {integrity: sha1-ATTqUUTlM7WU/B/yX/GU4jXFPs0=}
engines: {node: '>v0.4.10'}
dependencies:
js-yaml: 0.3.7
moo-server: 1.3.0
promised-io: 0.3.6
walker: 1.0.8
dev: true
/keyv/3.1.0:
resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==}
dependencies:
json-buffer: 3.0.0
dev: true
/kuler/2.0.0:
resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
dev: true
/latest-version/5.1.0:
resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==}
engines: {node: '>=8'}
@ -4591,16 +4512,6 @@ packages:
is-unicode-supported: 0.1.0
dev: true
/logform/2.3.0:
resolution: {integrity: sha512-graeoWUH2knKbGthMtuG1EfaSPMZFZBIrhuJHhkS5ZseFBrc7DupCzihOQAzsK/qIKPQaPJ/lFQFctILUY5ARQ==}
dependencies:
colors: 1.4.0
fecha: 4.2.1
ms: 2.1.3
safe-stable-stringify: 1.1.1
triple-beam: 1.3.0
dev: true
/loose-envify/1.4.0:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
@ -4652,12 +4563,6 @@ packages:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
dev: true
/makeerror/1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
dependencies:
tmpl: 1.0.5
dev: true
/marked/3.0.8:
resolution: {integrity: sha512-0gVrAjo5m0VZSJb4rpL59K1unJAMb/hm8HRXqasD8VeC8m91ytDPMritgFSlKonfdt+rRYYpP/JfLxgIX8yoSw==}
engines: {node: '>= 12'}
@ -4780,11 +4685,6 @@ packages:
uuid: 8.3.2
dev: true
/moo-server/1.3.0:
resolution: {integrity: sha1-XceVaVZaENbv7VQ5SR5p0jkuWPE=}
engines: {node: '>v0.4.10'}
dev: true
/ms/2.0.0:
resolution: {integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=}
dev: true
@ -4939,12 +4839,6 @@ packages:
wrappy: 1.0.2
dev: true
/one-time/1.0.0:
resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==}
dependencies:
fn.name: 1.1.0
dev: true
/onigasm/2.2.5:
resolution: {integrity: sha512-F+th54mPc0l1lp1ZcFMyL/jTs2Tlq4SqIHKIXGZOR/VkHkF9A7Fr5rRr5+ZG/lWeRsyrClLYRq7s/yFQ/XhWCA==}
dependencies:
@ -5188,10 +5082,6 @@ packages:
engines: {node: '>=0.4.0'}
dev: true
/promised-io/0.3.6:
resolution: {integrity: sha512-bNwZusuNIW4m0SPR8jooSyndD35ggirHlxVl/UhIaZD/F0OBv9ebfc6tNmbpZts3QXHggkjIBH8lvtnzhtcz0A==}
dev: true
/prop-types/15.7.2:
resolution: {integrity: sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==}
dependencies:
@ -5316,15 +5206,6 @@ packages:
util-deprecate: 1.0.2
dev: true
/readable-stream/3.6.0:
resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
engines: {node: '>= 6'}
dependencies:
inherits: 2.0.4
string_decoder: 1.1.1
util-deprecate: 1.0.2
dev: true
/readdirp/3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
@ -5521,10 +5402,6 @@ packages:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: true
/safe-stable-stringify/1.1.1:
resolution: {integrity: sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==}
dev: true
/safer-buffer/2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: true
@ -5647,12 +5524,6 @@ packages:
resolution: {integrity: sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==}
dev: true
/simple-swizzle/0.2.2:
resolution: {integrity: sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=}
dependencies:
is-arrayish: 0.3.2
dev: true
/sinon-chai/3.7.0_chai@4.3.4+sinon@11.1.2:
resolution: {integrity: sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==}
peerDependencies:
@ -5761,10 +5632,6 @@ packages:
dev: true
optional: true
/stack-trace/0.0.10:
resolution: {integrity: sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=}
dev: true
/stat-mode/1.0.0:
resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==}
engines: {node: '>= 6'}
@ -5932,19 +5799,10 @@ packages:
fs-extra: 10.0.0
dev: true
/text-hex/1.0.0:
resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
dev: true
/text-table/0.2.0:
resolution: {integrity: sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=}
dev: true
/timespan/2.3.0:
resolution: {integrity: sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=}
engines: {node: '>= 0.2.0'}
dev: true
/tiny-invariant/1.2.0:
resolution: {integrity: sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==}
dev: false
@ -5962,10 +5820,6 @@ packages:
rimraf: 3.0.2
dev: true
/tmpl/1.0.5:
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
dev: true
/to-fast-properties/2.0.0:
resolution: {integrity: sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=}
engines: {node: '>=4'}
@ -5983,8 +5837,9 @@ packages:
is-number: 7.0.0
dev: true
/triple-beam/1.3.0:
resolution: {integrity: sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==}
/tosource/1.0.0:
resolution: {integrity: sha1-QtiN0RZhi88A1hBt1URvNCeQL/E=}
engines: {node: '>=0.4.0'}
dev: true
/truncate-utf8-bytes/1.0.2:
@ -6124,11 +5979,6 @@ packages:
resolution: {integrity: sha512-6Gurc1n//gjp9eQNXjD9O3M/sMwVtN5S8Lv9bvOYBfKfDNiIIhqiyi01vMBO45u4zkDE420w/e0se7Vs+sIg+g==}
dev: true
/uglify-js/1.3.5:
resolution: {integrity: sha1-S1v/+Rhu/7qoiOTJ6UvZ/EyUkp0=}
hasBin: true
dev: true
/unbox-primitive/1.0.1:
resolution: {integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==}
dependencies:
@ -6285,12 +6135,6 @@ packages:
resolution: {integrity: sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==}
dev: true
/walker/1.0.8:
resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==}
dependencies:
makeerror: 1.0.12
dev: true
/which-boxed-primitive/1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
dependencies:
@ -6320,29 +6164,6 @@ packages:
string-width: 4.2.2
dev: true
/winston-transport/4.4.0:
resolution: {integrity: sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==}
engines: {node: '>= 6.4.0'}
dependencies:
readable-stream: 2.3.7
triple-beam: 1.3.0
dev: true
/winston/3.3.3:
resolution: {integrity: sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==}
engines: {node: '>= 6.4.0'}
dependencies:
'@dabh/diagnostics': 2.0.2
async: 3.2.2
is-stream: 2.0.1
logform: 2.3.0
one-time: 1.0.0
readable-stream: 3.6.0
stack-trace: 0.0.10
triple-beam: 1.3.0
winston-transport: 4.4.0
dev: true
/word-wrap/1.2.3:
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
engines: {node: '>=0.10.0'}
@ -6374,12 +6195,6 @@ packages:
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
dev: true
/wrench/1.3.9:
resolution: {integrity: sha1-bxPsNRRTF+spLKX2UxORskQRFBE=}
engines: {node: '>=0.1.97'}
deprecated: wrench.js is deprecated! You should check out fs-extra (https://github.com/jprichardson/node-fs-extra) for any operations you were using wrench for. Thanks for all the usage over the years.
dev: true
/write-file-atomic/3.0.3:
resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}
dependencies: