Promote the AI chat from a dashboard widget to a dedicated page:
- new sidebar item "Odin" under the Přehled section, gated on ai.use, → /odin
- new /odin route + Odin page (reuses the assistant component, with a light
ai.use guard)
- remove the widget from the dashboard
- rebrand the assistant header "Asistent" → "Odin" and give the thread more
height now that it owns the page
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 4 (final) of the "fully MUI" cleanup — no custom stylesheets remain
in src/admin (only the third-party quill.snow.css + leaflet.css imports).
- Login.tsx: every var(--glass-*/bg-*/text-*/accent-*/orb-*/border-*/
font-*/transition) in its sx/inline styles is now an MUI token
(bgcolor/color/borderColor: "background.paper" / "text.secondary" /
"divider" / "primary.main"), a channel-alpha (rgba(var(--mui-palette-
primary-mainChannel) / a)) for tints, or theme.applyStyles("dark", …)
for the glass-card shadow. The card sx is now a (theme)=>({}) callback.
- Restores the orb drift animation via the MUI keyframes() helper — the
@keyframes float had been dropped in Phase 1 (the dead-CSS scan missed
its use inside an sx animation string); recovered verbatim from git.
- ProjectFileManager: the fallback file-icon color uses
var(--mui-palette-text-secondary).
- variables.css deleted; its import removed from AdminApp (last one).
tsc -b --noEmit + npm run build clean. applyStyles dark-scheme output and
the channel-alpha pattern were both verified live in Chrome via the Quill
editor, which uses the identical constructs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 3 of the "fully MUI" cleanup.
- New src/admin/ui/RichText.tsx exports two theme-aware styled() wrappers:
RichEditorRoot (the .admin-rich-editor Quill overrides) and RichTextView
(the .admin-rich-text-view read-only output). All colors resolve via
theme.vars; picker/tooltip shadows use theme.applyStyles for the
light/dark difference; the active-button tint uses the primary channel.
- Dropped the ~170 dead font/size picker rules from the old stylesheet —
the editor toolbar exposes neither picker. Kept the .ql-font-* content
classes (shared by editor + view) so legacy stored HTML still renders.
- RichEditor uses <RichEditorRoot> (min-height still via --re-min-height);
InvoiceDetail + OrderDetail use <RichTextView> for the sanitized output.
- offers.css deleted; its import removed from AdminApp.
tsc -b --noEmit and npm run build clean. Verified the editor in Chrome
(light + dark): toolbar, editor surface, text, icon strokes and min-height
all correct and theme-reactive.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 2 of the "fully MUI" cleanup — eliminates two more stylesheets.
- base.css -> src/admin/GlobalStyles.tsx: the reset, typography,
scrollbar/::selection, theme cross-fade timing and all utility
classes now live in a single theme-aware MUI <GlobalStyles>, rendered
inside MuiProvider so every rule resolves against theme.vars (verified
reactive in both schemes). base.css deleted.
- attendance.css -> a styled("div") LocationMap in AttendanceLocation;
attendance.css deleted.
- App.tsx bootstrap loader is now fully self-contained (inline spinner
+ keyframes, theme-aware background read from the data-theme attr),
since it renders before MuiProvider/GlobalStyles mount — it no longer
depends on the removed .admin-spinner / var(--bg-primary).
tsc -b --noEmit and npm run build clean; verified in Chrome (light +
dark): body bg, text, fonts, .text-warning/.link-accent all correct.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 1 of the "fully MUI" CSS cleanup.
- base.css 429->317: drop dead .admin-sidebar/header/card/modal,
.admin-drag-handle/-kbd/-mono/-error-stack/-loading and the unused
float/pulse keyframes. Keep reset, typography, scrollbar,
::view-transition cross-fade, the live .admin-spinner (App.tsx
pre-React loader) and all utility classes.
- attendance.css 456->24: keep only the Leaflet .attendance-location-map
rules; the old hand-rolled Attendance page is MUI now.
- offers.css 642->417: keep only the Quill (.admin-rich-editor/.ql-*)
and .admin-rich-text-view rules; drop the dead offers table / filter /
lang-badge / row-state rules.
- plan.css deleted: the grid already lives in PlanGrid's styled()
wrapper; the last consumer (.plan-cat-color) is now an sx-styled
Box input in PlanCategoriesModal.
tsc -b --noEmit and npm run build both clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The page+component MUI migration has dropped all usages of these
stylesheets' classes. Verified by grep over src/**/*.{ts,tsx}: none of
their selectors are referenced as a className token anywhere.
Removed files + their imports from AdminApp.tsx:
forms.css, buttons.css, components.css, tables.css, datepicker.css,
filemanager.css, pagination.css, responsive.css, dashboard.css,
settings.css, invoices.css, warehouse.css
Kept: variables.css, base.css, plan.css (foundation), attendance.css
(live .attendance-location-map Leaflet container) and offers.css (live
.admin-rich-editor / .admin-rich-text-view + .ql-* Quill snow overrides).
The standalone <div className="admin-spinner"> in App.tsx remains styled
by base.css (buttons.css only held .admin-btn-scoped spinner modifiers).
Gates: tsc -b --noEmit (0), npm run build (ok), vitest (150 passed).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the three remaining hand-written admin-loading/admin-spinner
markup blocks with the kit <LoadingState /> component:
- AdminApp.tsx Suspense fallback
- AppShell.tsx loading branch
- PlanGrid.tsx no-data branch (plan-* classes untouched)
After this the only remaining admin-* classes in TSX are
admin-rich-editor (RichEditor/Quill) and admin-rich-text-view
(sanitized HTML in Order/Invoice detail).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wires the MUI AppShell into the admin route and deletes the legacy chrome (AdminLayout, Sidebar, layout.css). Spinner CSS (.admin-spinner/.admin-loading) lives in base.css and is unaffected. tsc -b clean, build OK, 148 tests pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds src/admin/pages/UiKit.tsx and registers a DEV-only <Route path="ui-kit">
sibling to <Route path="login">, outside the AdminLayout shell. The lazy import
uses the ternary `import.meta.env.DEV ? lazy(...) : null` pattern so Vite/Rolldown
evaluates the condition at build time and the UiKit chunk is entirely absent from
production bundles (confirmed: no UiKit-*.js in dist-client/assets after build:client).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wraps AdminApp in MuiProvider (ThemeProvider v7, defaultMode=dark) and
adds MuiColorSchemeSync to mirror ThemeContext's data-theme attribute
into MUI's JS color-scheme state so useColorScheme().mode stays in sync.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Replace hand-coded skeleton CSS/JSX with boneyard-js auto-generated bones
- Remove skeleton.css and @keyframes shimmer from base.css
- Add <Skeleton> wrappers with fixtures to all 25+ page components
- Generate 20 bone captures via boneyard CLI (CDP auth-gated capture)
- Refactor data fetching from useEffect+useState to TanStack Query
- Extract query hooks into src/admin/lib/queries/ and apiAdapter
- Add usePaginatedQuery hook replacing useApiCall/useListData
- Fix parseFloat || 0 anti-pattern in OfferDetail and OffersTemplates inputs
- Fix customer_id mandatory validation on offer creation
- Fix leave-requests comma-separated status filter (Prisma enum in: [])
- Add cross-entity cache invalidation for orders/offers/invoices/projects
- Make rate limits configurable via env vars (RATE_LIMIT_MAX, RATE_LIMIT_REFRESH, etc.)
- Add boneyard.config.json with routes and breakpoints
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Remove ProjectCreate page, POST /projects endpoint, and next-number endpoint
- Projects can only be created through orders (shared numbering sequence)
- Remove dead CreateProjectSchema and createProject service function
- Delete 'order' row from number_sequences (unused; code uses 'shared')
- Smart sequence release: decrement last_number only when deleting the highest number
- Fix received-invoices stats referencing non-existent is_deleted and amount_czk columns
- Update deploy instructions in CLAUDE.md (npm install, prisma migrate deploy)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- System settings page with tabs: Security, System, Firma
- Configurable attendance rules (break thresholds, rounding) from DB
- Configurable document numbering with template patterns ({YYYY}/{PREFIX}/{NNN})
- Dynamic logo upload (light/dark variants) served from DB instead of static files
- Email settings (SMTP from/name, alert/leave emails) configurable in UI
- Currency and VAT rate lists configurable, used across all modules
- Permissions simplified: offers.settings + settings.roles + settings.security → settings.manage
- Leaflet bundled locally, removed unpkg.com from CSP
- Silent catch blocks fixed with proper logging
- console.log replaced with app.log.info in server.ts
- Schema renamed: company-settings.schema → settings.schema
- App info section: version, Node.js, uptime, memory, DB status, NAS status
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>