ui(ai): Rework the assistant's confirmation cards - #106
Conversation
Three forms carried their own hardcoded currency lists instead of the shared one, so most of the currencies the app already knew about could not be picked anywhere. Someone could choose the rupee as their currency during onboarding and then find no way to open a wallet in it, because the wallet form offered nine currencies and that was not among them. The transaction and transfer forms build their lists from the wallets you hold, so a currency missing at the wallet could never appear there either. Every form now offers the shared list, which grows to cover the places people are actually paid: India, Brazil, Indonesia, the Philippines, Vietnam, Pakistan, Bangladesh, Turkey, Poland, Ukraine, Mexico and more. A wallet already holding something outside the list keeps working.
A transaction could carry any number of categories, which made "what did I spend this on" ambiguous and let one amount count under several headings at once. Picking a category is now a single choice rather than a growing list of chips. Opening a transaction saved before the limit keeps the first category it had; the rest fall away when it is saved.
Code Review SummaryThis PR delivers a significant upgrade to the AI assistant UI, introduces batch processing for AI actions, and fixes several stability bugs related to authentication and currency handling. 🚀 Key Improvements
💡 Minor Suggestions
|
| // be recorded as the Unix epoch rather than defaulted server-side. | ||
| if (value === '' || value === null || value === undefined) return; | ||
| // The payload carries one category as a list, while the control is single. | ||
| out[f.key] = f.key === 'categories' ? [value] : value; |
There was a problem hiding this comment.
The check for wrapping the category value in an array should rely on the field's type rather than the specific key name. The AI API might use various keys (e.g., category_id, categoryIds) for fields of type category, and all of them need to be wrapped as a single-item list for the current backend implementation.
| out[f.key] = f.key === 'categories' ? [value] : value; | |
| out[f.key] = f.type === 'category' ? [value] : value; |
A card asked people to approve changes described by internal ids, opened every field of an editing form whether or not anyone wanted to edit, and stacked one full-height card per record, so a request touching a handful of transactions scrolled for pages and cost a click each. A card now names what it will change and shows the fields at rest, opening the form only when someone chooses to edit. Changes proposed together arrive as a single card carrying the count, confirmed or dismissed as one, with each entry still reviewable on its own. Confirm and dismiss are quieter, the striped edge is gone, and status reads as a chip rather than a coloured border.
Granting admin took effect on the server but not in front of the person: the signed-in user is cached in a week-long cookie, and every path that refreshed it only did so when it was missing entirely, never when it was merely out of date. So a new admin saw no admin button and was turned away from the admin area until the cookie expired or they signed out and back in. The admin route now asks the server who they are on the way in. A failed check also signed people out. Any error at all while re-reading the user, a server hiccup or a dropped connection, cleared their session and left them at the login screen with nothing explaining why. Only an actual rejection ends a session now; everything else leaves them signed in and surfaces the error.
The readme said only that this is the web UI for Trakli, so a reader learned nothing about whether Trakli was for them before deciding to move on. The list under it put the things nobody else does between the things everybody does. It now opens with the person it is for, whose money is spread across cash, mobile money and more than one currency, and whom every other app quietly cannot serve. The list leads with what is ours, and the backend it needs is named up front rather than discovered at the setup step.
57ca992 to
af8944a
Compare
Deploying trakli-dev with
|
| Latest commit: |
af8944a
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://3c0206fc.trakli-dev.pages.dev |
| Branch Preview URL: | https://feat-agent-cards-currencies.trakli-dev.pages.dev |
| const props = withDefaults( | ||
| defineProps<{ block: ProposedActionBlock; sessionId: number; nested?: boolean }>(), | ||
| { nested: false } | ||
| ); |
There was a problem hiding this comment.
Since the ChatResultRenderer now uses unique IDs as keys (action-${block.id}), the component instance is reused when the block data is updated. Because state is a ref initialized once, it won't reflect status changes from the prop (e.g., if the action was executed by another part of the system) unless we watch the prop.
| ); | |
| const getStatus = (s: string) => { | |
| if (s === 'executed') return 'executed'; | |
| if (s === 'rejected') return 'rejected'; | |
| if (s === 'failed') return 'failed'; | |
| return 'pending'; | |
| }; | |
| const state = ref<'pending' | 'executed' | 'rejected' | 'failed'>(getStatus(props.block.status)); | |
| watch(() => props.block.status, (newStatus) => { | |
| state.value = getStatus(newStatus); | |
| }); |
| const open = ref(false); | ||
| const busy = ref(false); | ||
|
|
||
| const state = ref<'pending' | 'executed' | 'rejected' | 'failed'>( |
There was a problem hiding this comment.
Like the single action block, the batch block should watch its status prop to remain reactive if the server-side status changes while the component is mounted.
| const state = ref<'pending' | 'executed' | 'rejected' | 'failed'>( | |
| const getStatus = (s: string) => { | |
| if (s === 'executed') return 'executed'; | |
| if (s === 'rejected') return 'rejected'; | |
| if (s === 'failed') return 'failed'; | |
| return 'pending'; | |
| }; | |
| const state = ref<'pending' | 'executed' | 'rejected' | 'failed'>(getStatus(props.block.status)); | |
| watch(() => props.block.status, (newStatus) => { | |
| state.value = getStatus(newStatus); | |
| }); |
Deploying webui with
|
| Latest commit: |
af8944a
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c063c003.webui-9fh.pages.dev |
| Branch Preview URL: | https://feat-agent-cards-currencies.webui-9fh.pages.dev |
The counterpart to the webservice batch and currency work, plus two independent bug fixes that were in flight.
The assistant's confirmation cards named records by internal id, opened every edit field whether or not you wanted to edit, and stacked one full-height card per record. They now name what will change, stay compact until you choose to edit, and a set of changes proposed together arrives as one card confirmed or dismissed in one go.
Independent of that: