Skip to content

Commit 3bbae94

Browse files
authored
Surface history of a ledger inscription (#26)
* WIP show initial transaction time * Transaction dates surface in UI * Namespace logic ad types * Fix getOriginalTx function * Fix type QLDBHistory * Mini history graphic * Clean up
1 parent bc6ea6d commit 3bbae94

File tree

9 files changed

+160
-4546
lines changed

9 files changed

+160
-4546
lines changed

gui/package-lock.json

Lines changed: 27 additions & 4512 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gui/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@
1313
"@rollup/plugin-node-resolve": "^11.0.0",
1414
"@rollup/plugin-typescript": "^8.0.0",
1515
"@tsconfig/svelte": "^2.0.0",
16-
"node-sass": "^6.0.0",
1716
"rollup": "^2.3.4",
1817
"rollup-plugin-css-only": "^3.1.0",
1918
"rollup-plugin-livereload": "^2.0.0",
2019
"rollup-plugin-svelte": "^7.0.0",
2120
"rollup-plugin-terser": "^7.0.0",
21+
"sass": "^1.35.1",
2222
"svelte": "^3.0.0",
2323
"svelte-check": "^2.0.0",
2424
"svelte-preprocess": "^4.0.0",

gui/src/App.svelte

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,7 @@
11
<script lang="ts">
2-
import LedgerEntryComponent from './LedgerEntry.svelte';
3-
import type { LedgerEntry } from './types';
4-
5-
// double declaration to accomplish two things:
6-
// 1. the typing of `ledgerData`,
7-
// 2. its setting as a reactive store.
8-
let ledgerData: null | LedgerEntry[];
9-
$: ledgerData = null;
10-
11-
async function fetchData(): Promise<void | Error> {
12-
const res = await fetch('http://localhost:3000/list-docs');
13-
const data = await res.json();
14-
15-
if (res.ok) {
16-
ledgerData = data;
17-
} else {
18-
throw new Error(data);
19-
}
20-
}
2+
import * as Ledger from './Ledger/index';
3+
import { ledgerData } from './stores';
4+
ledgerData.set(Ledger.fetchData());
215
</script>
226

237
<style>
@@ -35,11 +19,16 @@
3519
</style>
3620

3721
<main>
38-
{#await fetchData()}
22+
{#await $ledgerData}
3923
<p>...waiting</p>
40-
{:then fulfilled}
41-
{#each ledgerData as item}
42-
<LedgerEntryComponent entry={item} />
24+
{:then data}
25+
{#each data as item}
26+
<Ledger.LedgerEntryComponent entry={item} />
27+
<div>
28+
<button on:click={() => Ledger.addHistoryTo(item)} href="#"
29+
>🕰 Show history</button
30+
>
31+
</div>
4332
{/each}
4433
{:catch error}
4534
<p style="color: red">{error.message}</p>

gui/src/History.svelte

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<script lang="ts">
2+
const w = 300;
3+
const h = 50;
4+
const padding = 10;
5+
</script>
6+
7+
<style type="text/scss">
8+
$grey: #ddd;
9+
svg {
10+
path {
11+
stroke: $grey;
12+
stroke-width: 2px;
13+
stroke-dasharray: 4 8;
14+
}
15+
circle {
16+
fill: $grey;
17+
}
18+
}
19+
</style>
20+
21+
<svg width={w} height={h}>
22+
<circle r={6} cx={padding} cy={h / 2} />
23+
<path d={`M${padding} ${h / 2} L${w - padding} ${h / 2}`} />
24+
</svg>
Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
<script lang="ts">
2-
import type { LedgerEntry } from './types';
2+
import * as Ledger from './index';
3+
import type { LedgerEntry, EntryHistory } from './index';
4+
import History from '../History.svelte';
35
export let entry: LedgerEntry;
6+
7+
let originalTX: null | EntryHistory = null;
8+
$: if (entry.history) {
9+
originalTX = Ledger.getOriginalTX(entry.history);
10+
}
411
const pathToThumbnail = (path: string): string =>
512
`http://localhost:3000/file/${path}.png`;
613
</script>
@@ -51,5 +58,9 @@
5158
{#if entry.one_file_hash}
5259
<pre>📁 {entry.one_file_hash}</pre>
5360
{/if}
61+
{#if entry.history}
62+
<History />
63+
<pre>🕰️ Added on {originalTX.originalTxDate}, {originalTX.originalTxTime}</pre>
64+
{/if}
5465
</div>
5566
</section>

gui/src/Ledger/index.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
export { default as LedgerEntryComponent } from './LedgerEntry.svelte';
2+
import { ledgerData } from '../stores';
3+
4+
export type LedgerEntry = {
5+
title: string;
6+
url: string;
7+
sku: string;
8+
screenshot_hash?: string;
9+
thumb_hash?: string;
10+
one_file_hash?: string;
11+
history?: QLDBHistory;
12+
};
13+
14+
export type EntryHistory = {
15+
originalTxDate: string;
16+
originalTxTime: string;
17+
};
18+
19+
export type QLDBHistory = QLDBHistoryItem[];
20+
21+
type QLDBHistoryItem = {
22+
blockAddress: {};
23+
data: {};
24+
metadata: { txTime: string };
25+
};
26+
27+
// @TODO: error handling!
28+
export async function fetchData(): Promise<LedgerEntry[]> {
29+
const res = await fetch('http://localhost:3000/list-docs');
30+
const data = await res.json();
31+
return data;
32+
}
33+
34+
/**
35+
* Handle the convoluted querying of a record's history
36+
* @param id string - the record's ID
37+
* @returns a promise of a history (an array of revisions)
38+
*/
39+
// @TODO: error handling!
40+
async function fetchItemHistory(id: string): Promise<QLDBHistory> {
41+
const res = await fetch(`http://localhost:3000/history/${id}`);
42+
const data = await res.json();
43+
return data;
44+
}
45+
46+
/**
47+
* Show a record's history in the UI: fetch this history
48+
* and add it to the `historyData` store
49+
* @param entry object - the record as represented in QLDB
50+
*/
51+
export async function addHistoryTo(entry: LedgerEntry) {
52+
const { sku } = entry;
53+
const itemHistoryData = await fetchItemHistory(sku);
54+
55+
ledgerData.update(async (d: Promise<LedgerEntry[]>) => {
56+
// let newStore;
57+
let newStore = await d.then(data => {
58+
const itemToUpdate = data.find(e => e.sku === sku);
59+
const updatedItem = { ...itemToUpdate, history: itemHistoryData };
60+
61+
return data.map((e: LedgerEntry) => {
62+
if (e.sku === sku) {
63+
return updatedItem;
64+
} else {
65+
return e;
66+
}
67+
});
68+
});
69+
return newStore;
70+
});
71+
}
72+
73+
export const getOriginalTX = (h: QLDBHistory): EntryHistory => {
74+
const originalTx = h[0];
75+
const originalTxDate = new Date(originalTx.metadata.txTime);
76+
return {
77+
originalTxDate: originalTxDate.toDateString(),
78+
originalTxTime: originalTxDate.toLocaleTimeString(),
79+
};
80+
};

gui/src/stores.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { Writable, writable } from 'svelte/store';
2+
import type { LedgerEntry } from './Ledger/index';
3+
4+
export const ledgerData: Writable<Promise<LedgerEntry[]>> = writable(null);

gui/src/types.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/qldb/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ async function getDocumentIdByField(
116116
value: string
117117
): Promise<string> {
118118
const query: string = `SELECT id FROM ${tableName} AS t BY id WHERE t.${field} = ?`;
119-
console.log(query)
120119
let documentId: string = undefined;
121120
await txn
122121
.execute(query, value)

0 commit comments

Comments
 (0)