Skip to content

chore(release): Prepare 1.1.1#81

Merged
nfebe merged 8 commits intomainfrom
dev
May 3, 2026
Merged

chore(release): Prepare 1.1.1#81
nfebe merged 8 commits intomainfrom
dev

Conversation

@nfebe
Copy link
Copy Markdown
Contributor

@nfebe nfebe commented May 3, 2026

[1.1.1] - 2026-05-03

Added

  • Image thumbnails for picked transaction attachments, with saved attachments rendered as cards on the edit form and a per-file remove control that deletes them server-side
  • Transactions list now refetches on tab focus so records synced from other clients (mobile, web) show up without forcing a re-login

Fixed

  • Transaction attachments are uploaded as multipart binary files instead of base64 JSON, so the backend file validator accepts them again
  • Files picked during a transaction edit are now actually uploaded (the update flow used to silently drop them)
  • The attachment picker appends to the existing selection instead of replacing it, and silently caps the total at five attachments to match the visible hint
  • Imports confirm step resolves targets by id and updates names reactively

nfebe added 7 commits April 26, 2026 19:01
The review screen now submits explicit wallet/party/category IDs and
pre-fills them from the user's existing records by exact name match.
Resolution is reactive: when the wallets/parties/categories caches
load after the analyzer response (common on a fresh page open), any
suggestion that was sitting unresolved gets re-matched automatically.

The confirm dialog only surfaces auto-create toggles when the analyzer
produced a name that doesn't match an existing record, so a fully
resolved batch shows a clean confirmation.

Signed-off-by: nfebe <fenn25.fn@gmail.com>
Transaction attachments were being sent as base64 strings inside the JSON
payload, so the backend file validator rejected every upload (failing the
"must be a file" check and tripping the size rule on the encoded length).

Selected files now travel as binary multipart parts to the dedicated upload
endpoint, so valid PNG, JPG, and PDF attachments are accepted again.
…clients

The transactions list relied on an in-memory cache that was only rebuilt
when the user logged out and back in. Records created on the mobile app
and synced to the server stayed invisible on the web until that reset,
even though they were saved on the backend.

The list now refetches when the page is opened and when the tab regains
focus, so newly synced transactions show up without forcing a relogin.
Creating a transaction routed picked files through the dedicated
multipart upload endpoint. Editing a transaction accepted files in the
form but never uploaded them, so attachments added during an edit
silently disappeared.

The update flow now performs the same upload step, so files added on
edit actually land on the transaction.
Attachments only appeared as filename chips: picked images had no
thumbnail, saved attachments were invisible during edit, and reopening
the picker replaced the previous selection instead of extending it.

Picked attachments now render as cards with image thumbnails or a label
tile for documents, successive picks append to the selection, and saved
attachments load through the auth-gated file endpoint with a per-file
remove control that deletes them from the transaction.
The "Max 5 files" hint was advisory only -- the picker happily added
more than five attachments, leaving the count to be rejected later by
the server.

The form now silently drops anything past five total attachments
(counting both saved and newly picked files), matching the hint.
Bumps UI to 1.1.1. CHANGELOG covers the patch: transaction attachments
finally upload as binary multipart files (and on edit, not just create),
the form previews picked images and renders saved attachments as cards
with per-file delete, the picker appends instead of replacing and caps
at five files, the transactions list refetches on tab focus so records
synced from other clients show up without re-login, and the imports
confirm step resolves targets by id.
@sourceant
Copy link
Copy Markdown

sourceant Bot commented May 3, 2026

Code Review Summary

This PR prepares version 1.1.1, introducing significant improvements to attachment handling and the data import workflow. It transitions file uploads to multipart/form-data and adds reactive ID resolution for imported records.

🚀 Key Improvements

  • Switched from base64 JSON uploads to multipart binary files in services/transactionApi.ts for better backend compatibility.
  • Added image thumbnails and card-based rendering for attachments in TransactionForm.vue.
  • Improved the import workflow by resolving entities by ID instead of name, reducing reactive mismatch bugs in useImports.ts.
  • Implemented auto-refresh on tab focus in TransactionsContentSection.vue to keep data synced across devices.

💡 Minor Suggestions

  • Cleanup unnecessary typeof document checks in lifecycle hooks.
  • Consider throttling the visibility-based refetch logic.

Copy link
Copy Markdown

@sourceant sourceant Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review complete. See the overview comment for a summary.

reader.readAsDataURL(file);
})
);
const remaining =
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current implementation silently drops files if the limit is exceeded. It is better to provide feedback to the user when files are ignored to prevent confusion.

Suggested change
const remaining =
const remaining = MAX_ATTACHMENTS - (newAttachments.value.length + existingAttachments.value.length);
const pickedFiles = Array.from(files);
if (pickedFiles.length > remaining) {
emit('error', t('Only {count} more files can be added', { count: remaining }));
}
for (const file of pickedFiles.slice(0, Math.max(0, remaining))) {

if (updated) {
let updatedOrWithFiles = updated;
const filesToUpload = Array.isArray(updates.filesToUpload) ? updates.filesToUpload : [];
if (filesToUpload.length > 0) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Files are uploaded after the transaction update. If the file upload fails, the transaction is already updated but the files are missing. Consider wrapping this in a more robust error handler or alerting the user specifically about the upload failure.

Suggested change
if (filesToUpload.length > 0) {
if (filesToUpload.length > 0) {
try {
const updatedWithFiles = await api.transactions.addFilesBulk(numericId, filesToUpload);
if (updatedWithFiles) updatedOrWithFiles = updatedWithFiles;
} catch (e) {
console.error('[updateTransaction] Error uploading files:', e);
emit('error', 'Transaction updated, but some files failed to upload.');
}
}

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 3, 2026

Deploying trakli-dev with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7f5c0ea
Status: ✅  Deploy successful!
Preview URL: https://85484ddf.trakli-dev.pages.dev

View logs

Commit message validation only ran on pull requests targeting main, so
non-conforming subjects could land on dev unnoticed and only surface
when the dev to main release PR was opened.

The check now also runs on pushes and pull requests against dev so
violations are caught at the original review.
Copy link
Copy Markdown

@sourceant sourceant Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review complete. See the overview comment for a summary.

}
};

onMounted(() => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The check for typeof document !== 'undefined' is unnecessary inside an onMounted hook in Nuxt/Vue 3, as onMounted only executes on the client-side where document is guaranteed to exist.

Suggested change
onMounted(() => {
onMounted(() => {
document.addEventListener('visibilitychange', handleVisibilityChange);
});

if (loadingPreviewIds.value.has(file.id)) return;
loadingPreviewIds.value.add(file.id);
try {
const blob = await api.transactions.fetchFileBlob(file.id);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using URL.createObjectURL is efficient but can lead to memory leaks if not properly managed. While you handle it in onUnmounted, long-lived forms that allow repeatedly adding/removing many files will accumulate revoked or orphan blobs. Consider revoking the old URL immediately when a user replaces a file or if the component logic allows.

Suggested change
const blob = await api.transactions.fetchFileBlob(file.id);
const blob = await api.transactions.fetchFileBlob(file.id);
const url = URL.createObjectURL(blob);
existingPreviews.value[file.id] = url;

field: 'wallet_id' | 'party_id' | 'category_id',
value: string
) => {
const id = value === '' ? null : Number(value);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When coercing the select value to a number, Number(value) will return 0 if the value is an empty string (though you handled empty string separately). It is safer to use parseInt(value, 10) to ensure consistent base-10 parsing of IDs.

Suggested change
const id = value === '' ? null : Number(value);
const id = value === '' ? null : parseInt(value, 10);

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying webui with  Cloudflare Pages  Cloudflare Pages

Latest commit: 7f5c0ea
Status: ✅  Deploy successful!
Preview URL: https://7380732b.webui-9fh.pages.dev
Branch Preview URL: https://dev.webui-9fh.pages.dev

View logs

@nfebe nfebe merged commit 7fbe7ce into main May 3, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant