Skip to content

Commit e9397fb

Browse files
thephezclaude
andcommitted
refactor(dashnote): trim duplication in lite companion
Merge the two list functions and number coercers, drop redundant epoch fields in favor of ISO-only timestamps (lex-sortable), and inline the shortId helper into copyIdSpan. 427 → 394 lines, behaviour unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e2955a9 commit e9397fb

1 file changed

Lines changed: 28 additions & 61 deletions

File tree

example-apps/dashnote/public/dashnote-lite.html

Lines changed: 28 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -146,37 +146,22 @@ <h2>Get note by ID</h2>
146146
return sdk;
147147
}
148148

149-
// List the latest notes across the whole contract. The contract's only
150-
// indices are byOwnerUpdated / byOwnerCreated (both compound on $ownerId),
151-
// so a true "newest across all owners" sort has no index to satisfy. We
152-
// issue a bare query (no where, no orderBy) and re-sort client-side by
153-
// $updatedAt desc. Same approach as listAllCards in dashmint-lite.
154-
async function listRecent(sdk, limit = DEFAULT_LIMIT) {
155-
const results = await sdk.documents.query({
156-
dataContractId: CONTRACT_ID,
157-
documentTypeName: DOC_TYPE,
158-
limit,
159-
});
160-
return normalizeNotes(results).sort(
161-
(a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0),
162-
);
163-
}
164-
165-
// List notes owned by a single identity. The byOwnerUpdated index requires
166-
// $ownerId to lead the orderBy, so we sort newest-first client-side.
167-
// Mirrors listMyNotes in src/dash/queries.ts in the React app.
168-
async function listByOwner(sdk, ownerId, limit = DEFAULT_LIMIT) {
169-
const trimmed = ownerId.trim();
170-
if (!trimmed) return [];
171-
const results = await sdk.documents.query({
172-
dataContractId: CONTRACT_ID,
173-
documentTypeName: DOC_TYPE,
174-
where: [['$ownerId', '==', trimmed]],
175-
orderBy: [['$ownerId', 'asc'], ['$updatedAt', 'asc']],
176-
limit,
177-
});
149+
// List notes from the contract. With no ownerId, issues a bare query (no
150+
// where/orderBy) since the contract's only indices are byOwnerUpdated /
151+
// byOwnerCreated, both compound on $ownerId — there is no index that
152+
// satisfies "newest across all owners". Same approach as listAllCards in
153+
// dashmint-lite. With an ownerId, uses the byOwnerUpdated index. Result
154+
// is always sorted client-side newest-first by $updatedAt.
155+
async function listNotes(sdk, ownerId, limit = DEFAULT_LIMIT) {
156+
const trimmed = ownerId?.trim() ?? '';
157+
const query = { dataContractId: CONTRACT_ID, documentTypeName: DOC_TYPE, limit };
158+
if (trimmed) {
159+
query.where = [['$ownerId', '==', trimmed]];
160+
query.orderBy = [['$ownerId', 'asc'], ['$updatedAt', 'asc']];
161+
}
162+
const results = await sdk.documents.query(query);
178163
return normalizeNotes(results).sort(
179-
(a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0),
164+
(a, b) => (b.updatedAtIso ?? '').localeCompare(a.updatedAtIso ?? ''),
180165
);
181166
}
182167

@@ -205,41 +190,31 @@ <h2>Get note by ID</h2>
205190
// Some result shapes wrap the document; .toJSON() unwraps it. Fallback to
206191
// treating `doc` itself as the data when toJSON isn't present.
207192
const data = (doc && typeof doc.toJSON === 'function') ? doc.toJSON() : doc;
208-
const createdAt = toTs(data.$createdAt);
209-
const updatedAt = toTs(data.$updatedAt);
210-
const revision = toRev(data.$revision ?? doc?.revision);
211193
return {
212194
id: String(id ?? data.$id ?? data.id ?? ''),
213195
ownerId: data.$ownerId ? String(data.$ownerId) : null,
214196
title: typeof data.title === 'string' ? data.title : null,
215197
message: typeof data.message === 'string' ? data.message : '',
216-
createdAt,
217-
createdAtIso: createdAt ? new Date(createdAt).toISOString() : null,
218-
updatedAt,
219-
updatedAtIso: updatedAt ? new Date(updatedAt).toISOString() : null,
220-
revision,
198+
createdAtIso: toIso(data.$createdAt),
199+
updatedAtIso: toIso(data.$updatedAt),
200+
revision: toNum(data.$revision ?? doc?.revision, 0),
221201
};
222202
}
223203

224-
// $createdAt / $updatedAt arrive as number, bigint, or numeric string.
225-
function toTs(value) {
204+
// $createdAt / $updatedAt / $revision arrive as number, bigint, or numeric string.
205+
function toNum(value, fallback) {
226206
if (typeof value === 'number' && Number.isFinite(value)) return value;
227207
if (typeof value === 'bigint') return Number(value);
228208
if (typeof value === 'string' && value) {
229209
const n = Number(value);
230-
return Number.isFinite(n) ? n : null;
210+
if (Number.isFinite(n)) return n;
231211
}
232-
return null;
212+
return fallback;
233213
}
234214

235-
function toRev(value) {
236-
if (typeof value === 'number' && Number.isFinite(value)) return value;
237-
if (typeof value === 'bigint') return Number(value);
238-
if (typeof value === 'string' && value) {
239-
const n = Number(value);
240-
return Number.isFinite(n) ? n : 0;
241-
}
242-
return 0;
215+
function toIso(value) {
216+
const n = toNum(value, null);
217+
return n != null ? new Date(n).toISOString() : null;
243218
}
244219

245220
// ============================================================================
@@ -280,16 +255,10 @@ <h2>Get note by ID</h2>
280255

281256
// Truncate an id to head…tail for compact display while keeping the full
282257
// value on the element via data-id (for copy) and title (for hover).
283-
function shortId(id) {
284-
if (!id) return '';
285-
const s = String(id);
286-
return s.length > 16 ? `${s.slice(0, 6)}${s.slice(-6)}` : s;
287-
}
288-
289258
function copyIdSpan(fullId) {
290259
const span = document.createElement('span');
291260
span.className = 'copy-id';
292-
span.textContent = shortId(fullId);
261+
span.textContent = fullId.length > 16 ? `${fullId.slice(0, 6)}${fullId.slice(-6)}` : fullId;
293262
span.dataset.id = fullId;
294263
span.title = fullId;
295264
return span;
@@ -304,7 +273,7 @@ <h2>Get note by ID</h2>
304273
}
305274
// One-line muted footer: timestamp · rev (if >1) · doc-id [· owner]
306275
const footer = makeDiv('footer');
307-
const isEdited = n.updatedAt != null && n.createdAt != null && n.updatedAt !== n.createdAt;
276+
const isEdited = n.updatedAtIso != null && n.createdAtIso != null && n.updatedAtIso !== n.createdAtIso;
308277
const tsLabel = isEdited ? 'Updated' : 'Created';
309278
const tsValue = fmtDate(isEdited ? n.updatedAtIso : n.createdAtIso);
310279
if (tsValue) footer.append(`${tsLabel} ${tsValue}`);
@@ -351,9 +320,7 @@ <h2>Get note by ID</h2>
351320
const owner = ownerInput.value.trim();
352321
recentResultEl.replaceChildren(statusLine('Querying…'));
353322
try {
354-
const notes = owner
355-
? await listByOwner(sdk, owner, DEFAULT_LIMIT)
356-
: await listRecent(sdk, DEFAULT_LIMIT);
323+
const notes = await listNotes(sdk, owner, DEFAULT_LIMIT);
357324
if (notes.length === 0) {
358325
const msg = owner
359326
? `No notes found for owner "${owner}".`

0 commit comments

Comments
 (0)