Conversation
* feat(build): migrate build system to Vue 3 + bootstrap-vue-next Phase 1 of Vue 3 migration (aw-webui#772): - vue 2.7 -> 3.5, vue-router 3 -> 4 - bootstrap-vue -> bootstrap-vue-next (bootstrap 4 -> 5) - chart.js 3 -> 4 (required by vue-chartjs v5) - @vitejs/plugin-vue2 -> @vitejs/plugin-vue - Remove webpack/@vue/cli-* packages entirely - Remove Vue 2-only packages: vue-datetime, vue-color, vue-awesome, vuedraggable v2 - Add vuedraggable v4, @fullcalendar/vue3 v6 - Update main.js: createApp() + createBootstrap() (bootstrap-vue-next API) - Update route.js: createRouter() + createWebHashHistory() (Vue Router 4 API) - Update stores/index.js: remove PiniaVuePlugin (Vue 2 only) - Update filters.js: export functions instead of Vue.filter() (removed in Vue 3) - Fix Vue.extend() -> defineComponent() in 3 components - Fix Calendar.vue: @fullcalendar/vue -> @fullcalendar/vue3 - Fix TimelineBarChart.vue: vue-chartjs/legacy -> vue-chartjs (v5 API) - Add vite.config.js stub plugin for Vue 2-only packages - Disable transformAssetUrls to allow runtime-served assets (logo.png) - Add IconPlaceholder.vue stub for vue-awesome icon component - Fix Header/Footer component names (reserved in Vue 3 ESLint rules) Build: 2191 modules transformed, dist generated successfully. Components still use Vue 2 Options API - individual migration in follow-up commits. * fix(deps): upgrade eslint-config-typescript to v11 for Vue 3 compatibility @vue/eslint-config-typescript ^10 requires eslint-plugin-vue ^8, which conflicts with ^9 (needed for Vue 3). Upgrading to ^11 resolves the ERESOLVE peer dependency conflict that was breaking npm ci in CI. * fix(ci): fix ESLint and Jest config for Vue 3 migration - Bump ESLint ecmaVersion from 2017 to 2020 (supports dynamic import()) - Remove broken regex-style override patterns (ESLint uses globs, not regex) - Remove recursive vue-eslint-parser override that caused stack overflow - Replace @vue/cli-plugin-babel/preset with @babel/preset-env in babel config - Remove @vue/cli-plugin-unit-jest preset from Jest config (package removed) - Replace @vue/vue2-jest with @vue/vue3-jest for .vue file transforms - Add testEnvironmentOptions to fix @vue/test-utils browser build resolution - Add @vue/vue3-jest to devDependencies * fix(e2e): bind Vite dev server to 127.0.0.1 for e2e tests The e2e tests connect to http://127.0.0.1:27180 but Vite defaults to binding on 'localhost' which may resolve to ::1 (IPv6) on Ubuntu 24.04 CI runners, causing ConnectionRefused errors. * fix(vue3): migrate v-model events, lifecycle hooks, and filter syntax Vue 3 breaking changes that were missed in the initial migration: - $emit('input') → $emit('update:modelValue') in all custom components that support v-model (InputTimeInterval, QueryOptions, SelectCategories, SelectCategoriesOrPattern, ColorPicker). This was causing Timeline view to be stuck on "Loading..." because daterange was never emitted. - beforeDestroy → beforeUnmount lifecycle hook (InputTimeInterval, Activity, CategorizationSettings). Vue 3 renamed this hook. - {{ value | filterName }} pipe syntax → {{ filterName(value) }} function calls across all 14 affected components. Vue 3 removed global filters; functions are imported from ~/util/filters and exposed via methods. * fix(vue3): address Greptile review findings - Header.vue: fix Vue 2 slot syntax (slot= → #) on Activity and Tools dropdown buttons — broken in Vue 3, caused empty navbar dropdowns - vite.config.js: give setCsp/autoInject unique plugin names ('set-csp' and 'auto-inject') instead of duplicate 'html-transform' - package.json: move vue-router from devDependencies to dependencies (it's a runtime import, not a build tool) * fix(vue3): set $aw global property before app.mount() In Vue 3, app.config.globalProperties must be set before mounting. Move $aw alongside the other global properties (PRODUCTION, COMMIT_HASH, $isAndroid) before the mount() call. configureClient() stays after mount since it depends on the settings store being initialized. * fix(vue3): Font Awesome icons, Bootstrap 5 classes, Vue 3 patterns Major visual fixes for the Vue 3 migration: - Replace empty IconPlaceholder with @fortawesome/vue-fontawesome — maps all 50+ vue-awesome icon names to Font Awesome 6 equivalents, fixing missing icons throughout the app (navbar, footer, buckets, settings, etc.) - Migrate Bootstrap 4 → 5 utility classes across all 30+ Vue files: .ml-* → .ms-*, .mr-* → .me-*, .pl-* → .ps-*, .pr-* → .pe-*, .float-left → .float-start, .float-right → .float-end, .text-left → .text-start, .text-right → .text-end - Fix Buckets.vue: replace Vue 2 $root.$emit modal control with bootstrap-vue-next v-model pattern - Fix Home.vue: add null guard for serverStore.info access that crashed render before server info loaded - Fix Buckets.vue: add null guard for serverStore.info.hostname - Update vite.config.js: add comment explaining why transformAssetUrls: false is needed (runtime /logo.png from aw-server, not a build asset) Co-authored-by: Bob <bob@superuserlabs.org>
* fix(vue3): remove dead vue-awesome imports * fix(vue3): update color picker model binding * fix(vue3): align ColorPicker v-model prop * fix(vue3): resync ColorPicker on prop updates
…t in EventEditor (ActivityWatch#839) * fix(vue3): replace datetime component with native datetime-local input in EventEditor * fix(vue3): restore seconds precision in EventEditor datetime inputs Add step='1' to datetime-local inputs and use HH:mm:ss format strings to prevent silent truncation of seconds when editing event timestamps. Without this, any edit rounded timestamps to the nearest minute and corrupted duration arithmetic by up to 59 seconds. --------- Co-authored-by: TimeToBuildBob <223556219+Copilot@users.noreply.github.com>
Master gained a lot since the Vue 3 branch was cut (i18n, new views and tests), so bring those parts up to Vue 3 as well: - Replace vue-d3-sunburst (Vue 2 only, stubbed out so far) with a small D3-backed zoomable sunburst, and drop the Vue 2 stub plugin from the Vite config since nothing imports the stubbed packages any more. - Compare query options with toRaw() in the activity store: Pinia state reads return reactive proxies, so the identity checks never matched and a failed query left the progress bar stuck. - Port master's component tests to Vue Test Utils 2 (global mocks/stubs, props, unmount), vue-router 4's resolve() and vue-i18n's global locale. - Compile pug in Jest with the html doctype, like @vitejs/plugin-vue, so shorthand slots such as `template(#header)` parse. - Rename the Header/Footer components (reserved HTML names) and let ESLint parse ES2021 numeric separators.
After the Vue 3 migration the app built and tests passed, but most of the
UI didn't render when run against a server:
- bootstrap-vue-next components were never registered (createBootstrap()
only installs its plugins), so every `b-*` tag was an unknown element.
Register all components and directives globally, as Vue.use(BootstrapVue)
did, and use the canonical names instead of bootstrap-vue's aliases
(b-btn, b-input, b-select, b-checkbox).
- Port templates to bootstrap-vue-next's API: alerts are shown with
v-model instead of `show` (they were all hidden) and emit `close`
instead of `dismissed`; form controls bind `model-value` instead of
`value`/`checked`; dropdowns align with `end`; modals use `no-footer`;
table sorting takes `[{ key, order }]`; Bootstrap 5 dropped the
input-group append/prepend wrappers and `.close`.
- Replace the Vue 2 modal/toast APIs ($bvModal, $bvToast, v-b-modal and
$root `bv::` events) with v-model state and useToastController(); the
event editor now takes `v-model:open`.
- /activity/:host showed "page not found": vue-router 4 doesn't resolve
the relative `redirect: 'view/'`, and absent optional params are passed
as '' and overrode the prop defaults.
- The activity dashboard used vuedraggable 2's API (v4 needs an #item
slot and item-key), so it rendered no visualizations.
- Async components declared as `() => import()` rendered "[object
Promise]"; use defineAsyncComponent.
- v-for and v-if on the same element in the category tree: v-if now wins,
so expansion was ignored.
- The async error mixin crashed on Vue 3's single errorCaptured hook and
re-wrapped the component's shared methods on every new instance.
- The timeline bar chart's responsive options were on its data object,
so it kept an aspect ratio; give it a fixed-height container.
- Add Font Awesome icons for names that were missing from the map.
- Keep Bootstrap 4's link style (underline on hover only), and fix the
activity view tabs and header spacing under Bootstrap 5.
- Upgrade to Vite 7, which supports the esbuild version master pins, and
replace every CSP placeholder in index.html in dev.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1012 +/- ##
==========================================
- Coverage 63.30% 62.98% -0.32%
==========================================
Files 52 53 +1
Lines 3608 3658 +50
Branches 840 898 +58
==========================================
+ Hits 2284 2304 +20
+ Misses 1309 1271 -38
- Partials 15 83 +68 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
TimeToBuildBob
left a comment
There was a problem hiding this comment.
Reviewed against the #772 list and a live checkout of cc81fb5.
The slice is right: rebase vue3 onto current master, stay on bootstrap-vue-next, and make the UI actually render. The route redirect, paramsAsProps, vuedraggable #item slot, defineAsyncComponent, CategoryTree v-for/v-if split, chart :data/:options, and dropping $bvModal/$bvToast all look correct. Unit tests (478) plus e2e on aw-server / aw-server-rust v0.12.3b18 are green.
Not merge-ready yet. Three concrete breakages, plus one CI regression vs master:
- Filters cannot open. Activity still uses Vue 2
:pressed.sync. In Vue 3 that does not write back, soshowOptionsnever becomes true. - Settings / Trends
@changestill assume bootstrap-vue's value payload.startOfDay, locale, landing page, default duration, and the Trends host selector assign$event. bootstrap-vue-next emits the native event there;startOfWeekalready usesv-modeland is the pattern to copy. - New sunburst hover/zoom identity.
rootismarkRaw, but assigning a descendant to reactivehovered/zoomedproxies it.isHighlightedusesancestors().includes(d)andzoomTousesd === this.zoomed, so hover dims the hovered arc and clicking the center cannot zoom out. - e2e vs aw-server-rust
masteris a new failure. Same matrix cell is green on Vue 2master. Here: Home passes, Activity stays on.aw-loading/ "Loading...", TestCafe refreshes twice, then Chrome disconnects (6/8 failed). The v0.12.3b18 jobs passing is not enough — this cell is part of the required matrix.
Lower priority, not merge-blocking on their own:
- Dashboard
visKeyisview.id + '-' + indexOf(el), so keys move with position during drag. Visualizations are already index-addressed (el_id), but a stable key (or an id on each element) would avoid remounts. - Dark theme /
dark.cssunder Bootstrap 5, and the 0.25 → 1.x bump, can stay follow-ups as you listed. jqueryis still inpackage.jsonwith no remaining source import. Fine to drop later.
Please keep shadcn-vue out of this PR. Once the four items above are fixed, this is the right vehicle to get Vue 3 onto master.
|
@TimeToBuildBob Might be worth checking this against https://bootstrap-vue-next.github.io/bootstrap-vue-next/docs.html and https://bootstrap-vue-next.github.io/bootstrap-vue-next/docs/migration-data/ Also wondering if this should really target master, or if it should simply be force-pushed to the vue3 branch or create a |
|
Good questions. My read: 1. migration-data — yes, use it as the checklist. It's now a machine-readable KB (
The sync-modifier class is exactly what got missed by eyeballing, so a systematic pass over the KB is worth it. 2. Branch target — don't target The existing Mechanics — there's a trap worth naming first: if
I have no write access on 3. Wait until after v0.14.0 stable + patches — agree. Gate: v0.14.0 stable tagged, patch releases done, then the Status on the PR: my CHANGES_REQUESTED review stands (Filters-panel |
…urst - bootstrap-vue-next form controls emit update:modelValue, not change, so `@change` handlers received the native Event: settings stored the event as their value and the Trends host picker navigated to it. Bind with v-model (lazy for the start-of-day time input) or update:model-value. - The activity filters toggle used Vue 2's `:pressed.sync`, so the panel could not be opened; use v-model:pressed. - Key dashboard visualizations by a stable per-element id instead of their position, so reordering doesn't hand one visualization's instance (and local state) to another. - Mark every sunburst node raw, not just the root: hovered/zoomed nodes went through reactive state and no longer matched the raw nodes, so the hovered arc was dimmed and the zoomed arc couldn't zoom back out. - Pick the sunburst center color from the applied theme setting; this branch loads dark.css without a `.dark` class.
|
@greptile review |
bootstrap-vue-next reads lazy from the v-model modifiers, not a prop, so the bare `lazy` attribute saved (and reloaded settings) on every input.
|
@greptile review |
|
Follow-up after 5cc51e6 / 6f00379 — I re-ran the bootstrap-vue-next migration-data pass on the new head. The earlier miss is gone: Filters is Review items 1–3 are verified in the tree. The aw-server-rust Branch-target rec is unchanged: keep this off |
The e2e tests stalled for minutes per view and the aw-server-rust master job failed with the browser disconnecting. Two causes, both reproducible locally with a fresh Vite cache: - Vite only scanned index.html for dependencies, so it discovered those of each lazily loaded route on first visit, re-optimized and force- reloaded the page (answering in-flight imports with 504 "Outdated Optimize Dep"). Scan all source files at startup instead. - The period usage chart and the simple timeline are async components that only drew when their data prop changed after mounting. When the data loaded first (as with slower chunk loading), they stayed on "Loading..." forever. Draw data that is already there on mount.
|
@greptile review |
getActiveHistoryAroundTimeperiod fills unfetched periods with zero- duration placeholders, so drawing whatever data was there on mount could show an all-empty, clickable chart while the history query was still running. Mark the placeholders and only draw on mount once at least one period has actually been fetched.
|
@greptile review |
@TimeToBuildBob all four items from your review are addressed, and CI is fully green on 5759265, including the aw-server-rust
Greptile is at 5/5 with no open threads. Could you re-review when you have a chance? On the branch target, I'll leave that to @ErikBjare. |
TimeToBuildBob
left a comment
There was a problem hiding this comment.
@0xbrayo Re-reviewed 5759265. The four requested changes are in the tree, and CI is fully green — including the aw-server-rust master e2e cell.
- Filters:
v-model:pressed - Settings/Trends:
v-model/v-model.lazy/@update:model-value(remaining@changeis native) - Sunburst: every d3 node is
markRaw; hover regression test is there - rust-master e2e: Vite
optimizeDeps.entries+ PeriodUsagehasFetchedHistory
Approving the code. Still draft — don't merge to master until after v0.14.0 stable + patches. Branch target is still Erik's call.
Follow-up to #772 / #773: the
vue3integration branch rebased onto currentmaster, plus the fixes needed for the UI to actually render. Stays on bootstrap-vue-next — no UI library change.Commits
vue3commits, rebased — feat(build): migrate to Vue 3 + bootstrap-vue-next #773, fix(vue3): remove dead vue-awesome imports #831, fix(vue3): replace datetime component with native datetime-local input in EventEditor #839. feat(categories): support field-scoped regex rules #840 is dropped sincemasteralready has it as feat(categories): support field-scoped regex rules on master #952. The conflicts were mostlymaster's newer templates (i18n, redesigns); those keepmaster's markup, with feat(build): migrate to Vue 3 + bootstrap-vue-next #773's mechanical Vue 3 changes (filters, BS5 utility classes,update:modelValue, lifecycle hooks) re-applied across the tree.fix(vue3): finish migration after rebasing onto master— brings code added tomastersince the branch was cut up to Vue 3: vue-i18n 8 → 11, component tests ported to Vue Test Utils 2, and atoRaw()fix in the activity store (Pinia returns reactive proxies, so thequery_optionsidentity checks never matched and a failed query left the progress bar stuck). It also replaces the stubbedvue-d3-sunburst(Vue 2 only) with a small D3 sunburst, so the Vue 2 stub plugin is gone fromvite.config.js.fix(vue3): make the bootstrap-vue-next UI render— the issues reported in Attempt at Vue 3 migration #772:createBootstrap()doesn't register components, so everyb-*tag was unresolved. All components and directives are now registered globally, likeVue.use(BootstrapVue)did.v-modelinstead ofshow(they were all hidden) and emitcloseinstead ofdismissed.model-valueinstead ofvalue/checked.end; modals useno-footer.BTablesort-bytakes[{ key, order }]..close.$bvModal,$bvToast,v-b-modaland$rootbv::events are replaced withv-modelstate anduseToastController(). The event editor now takesv-model:open./activity/:host"page not found": the relativeredirect: 'view/'doesn't resolve in vue-router 4, and absent optional params arrive as''and override the prop defaults.#itemslot (the dashboard rendered nothing).() => import()async components rendered[object Promise]and now usedefineAsyncComponent.v-if+v-foron one element in the category tree ignored expansion.errorCaptured.masterpins esbuild 0.28 inoverrides, which Vite 6's dev server can't pre-bundle dependencies with.Testing
npm run buildandnpm testpass (478 tests; new regression tests for the activity route redirect, the sunburst and the dashboard's draggable keying).Known gaps
static/dark.csswas written against Bootstrap 4 class names and needs a pass under Bootstrap 5.^0.25(latest is 1.2); upgrading is left for a separate PR.master, because the chart isn't passed the period length.