Commit Graph

26 Commits

Author SHA1 Message Date
fs
4cf4ccc595 fix(ui): robust grid table states — natural row heights, themed pagination, DOM skeleton
Rows expanded unboundedly because `fixedHeader: true` + a fixed `height`
forced a scroll container that filled itself with stretched rows on short
result sets. Pagination text rendered white-on-white because the shared
button base (app-shell.css) redefines `--app-color` as `--app-primary-inverse`
in the button scope, so `color: var(--app-color)` in an override resolves
to white. Sort-column headers looked misaligned because Grid.js uses floats
to place label and sort icon, which ignore the cell's vertical-align.

- Sticky header is now opt-in; default scroll behavior is page-level.
- Row heights come from padding + line-height only (no fixed `height`).
- Pagination buttons theme via `--app-background-color`/`--app-color`
  redefinition (the Pico convention) using `--app-form-element-color`,
  which is not shadowed in the button scope. `margin-inline-start: auto`
  on `.gridjs-pages` guarantees right-alignment even without a summary.
- Sort headers use `inline-block` + `vertical-align: middle` instead of
  vendor floats so label and icon share one cross-axis center.
- Loading UX replaced with a real `<table>` skeleton that mirrors the
  final column count + outer layout (card + footer with summary and
  5 pager placeholders). Grid.js mount point is hidden via
  `.app-grid-shell-loading > :not(.app-grid-skeleton)` — vendor wraps
  its own `.gridjs-container` one level deeper, so a direct-child
  selector on the mount element is required.
- Re-fetch state shows a thin top progress bar + faded tbody (GitHub
  pattern) so existing data stays as context.
- `prefers-reduced-motion` disables all skeleton/progress animations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 20:22:51 +02:00
fs
0c8ccae0fb feat(ui): refresh core grid table ux foundation 2026-04-22 19:56:23 +02:00
fs
811588290c feat(core): detail drawer + address book list redesign
Introduces a reusable core detail-drawer primitive that slides in from the
right and loads any view via a `*-fragment(none).phtml` endpoint. Bundles the
address book list overhaul that is its first consumer.

Core additions:
- `app-detail-drawer.js` — generic drawer with stepper, focus trap, body
  scroll-lock, URL-hash deep-linking, session-expiry detection
- `app-fragment-init.js` — auto-wires tabs/lookups/confirm/file-upload/
  fslightbox inside injected HTML; consumers do not re-initialize components
- `app-focus-trap.js` — shared focus-trap + refcounted scroll-lock, used by
  both filter-drawer and detail-drawer
- `getHtml()` in `app-http.js` + `SessionExpiredError`; drawer reloads the
  page on auth redirect instead of rendering the login form in the panel
- `DetailDrawerFragmentContractTest` enforces that every `initDetailDrawer`
  consumer ships matching `*-fragment($id).php` + `*-fragment(none).phtml`

Address book list:
- Grid collapses from 9 columns to 4 (identity / context / phone / actions)
  with a two-line identity cell (avatar + name + email)
- Tenant register tabs above the grid using the `app-list-tabs` partial;
  tenant filter wired via hidden toolbar field so grid.js forwards it on
  every data fetch
- Profile body extracted to a shared partial so the full-page view and the
  new drawer fragment share the same markup
- New i18n keys for the drawer/list labels

Also refactors `app-filter-drawer` to reuse the shared focus-trap and
scroll-lock instead of maintaining its own copy, and documents the
detail-drawer convention in CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 15:22:26 +02:00
fs
12356e2266 feat(core): generic CSV export primitive + helpdesk domains consumer
Add a reusable CSV-export building block to the core so any Grid.js list
page can gain a filter/sort-aware download with two clicks of glue.

Core primitive:
- core/Service/Export/CsvExportService: flavor-aware writer (plain CSV
  or Excel-compatible UTF-8+BOM+semicolon), with OWASP-aligned formula-
  injection escape (=, @, +, -, TAB, CR) applied to both rows *and*
  headers. Value objects for columns (ExportColumn) carry an extractor
  closure and an allowSignedNumeric flag for phone-number-shaped cells.
- core/Support/helpers/export.php: thin HTTP layer (exportSendCsv,
  exportCapLimit, exportResolveFlavor, exportRequireGetRequest) reusing
  the requestInput() contract for GR-CORE-003 consistency. Filename is
  sanitized and length-clamped; callers must still enforce auth.
- templates/partials/app-list-export-dropdown.phtml: zero-config
  <details class="dropdown"> with CSV + Excel triggers.
- web/js/core/app-list-export.js: initListExport({ gridConfig, exportUrl })
  mirrors the current grid filters + sort onto the export URL and
  navigates, preserving session cookies for download.

First consumer — Helpdesk domains:
- DomainListService extracts the shared filter/enrich/sort logic from
  domains-data so the grid endpoint and the new domains/export endpoint
  cannot drift.
- domains/export endpoint delegates to DomainListService, declares
  ExportColumns (with translated level labels), and exits via
  exportSendCsv.
- domains-data now ~20 lines, delegating to DomainListService.

Tests:
- CsvExportServiceTest (10 cases): both flavors, BOM/no-BOM, formula
  escapes incl. TAB/CR, header escape, signed-numeric allowlist,
  quoting, multiline, empty columns, generator-compatible iterable.
- ExportHelpersTest (5 cases): exportCapLimit bounds.
- DomainListServiceTest (8 cases): filter, search, "all" sentinel,
  sort, paging, enrichment, BC failure, tenant-scoped security filter.

Gates: PHPUnit green, PHPStan clean on touched files, module:sync ok.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 21:57:19 +02:00
fs
6ac685084d Feature: Security Level mit Notiz für Domains
Implementiert ein Dialog-basiertes UI zum Bearbeiten des Security Levels
mit optionaler Notiz-Funktion für Helpdesk-Domains.

Backend:
- DomainSecurityLevelRepository: CRUD für security_levels mit note-Spalte
- DomainSecurityLevelService: Business-Logik mit Batch-Enrichment
- security-level-data() Endpoint: AJAX + Full-Page POST mit CSRF
- Migration 010: note TEXT-Spalte hinzugefügt
- Bugfix: findByTenantAndDomainNo gibt null bei leerem Array zurück

Frontend (Domain-Liste):
- Badge in Grid klickbar → öffnet Modal-Dialog
- Dialog mit Level-Select + Notiz-Textarea
- AJAX-Save mit Live-Badge-Update ohne Reload
- Event-Delegation für dynamische Grid-Inhalte

Frontend (Domain-Detail):
- Notiz-Feld im Security-Level-Formular
- PRG-Pattern mit Flash-Messages

Core:
- app-http.js: DEFAULT_HEADERS auf XMLHttpRequest für CSRF-Kompatibilität

i18n:
- Keys: Priority, Note, Optional note, Security level updated

Tests:
- DomainSecurityLevelServiceTest: CRUD + Batch-Enrichment
2026-04-21 13:43:16 +02:00
fs
c3de7d4238 feat(js): enforce global lifecycle hard-cuts and helpdesk list adapter 2026-04-20 23:01:54 +02:00
fs
f189ef9df6 feat(js): add app-http contracts and migrate helpdesk runtime layer 2026-04-20 22:31:13 +02:00
fs
31ecb40235 refactor: clean up web assets and consolidate PHP helpers
- Remove 2079 unused bootstrap-icons SVGs + min.css (~9.3 MB saved, app uses font approach only)
- Remove unused editorjs.umd.js (only .mjs is imported)
- Extract shared syncControlState into app-conditional-controls.js, deduplicate SSO/LDAP toggles
- Add settingToBool() helper to DRY up repeated bool-parsing pattern across 6 call sites
- Merge single-function auth.php into app.php, delete auth.php
- Extract 9 branding functions from app.php into dedicated branding.php (app.php 709→528 lines)
- Remove empty web/img/ directory

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 21:31:59 +02:00
fs
a0d7670dd7 feat(helpdesk): align module with core list/drawer standards
- add helpdesk module pages, services, settings and tests

- standardize debtor list on drawer/grid contracts and robust filter drawer behavior

- add helpdesk aside panel navigation and settings visibility provider

- switch primary list slug to helpdesk/debitor and remove helpdesk/search compatibility

- include required core contract updates for list contracts and detail/drawer integration
2026-04-02 17:48:27 +02:00
fs
211149b3f6 fix: improve Grid.js table header alignment and column min-width
- Add default minWidth (100px) to all grid columns via normalizeGridColumns
  to prevent header truncation when data entries are short
- Fix inconsistent th heights by setting .gridjs-th-content line-height
  to 24px (matching the sort button height) so sortable and non-sortable
  columns render at uniform height
- Remove dead button.gridjs-sort height:15px rule (was overridden by 24px)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 21:23:39 +01:00
fs
1c5648c727 fix: replace grid action column with link-column on primary data cell
Remove the dedicated "Edit"/"Open" action button column from all list
pages. Instead, wrap the primary data column (name, description, subject,
etc.) in a clickable <a> link via the new rowInteraction.linkColumn option.

Double-click, Enter-key, and click-to-focus row navigation preserved.
Pages with explicit actions config are unaffected. Address-book opts out
of auto-wrapping (linkColumn: false) and renders the link in its own
formatter to avoid nested <a> with avatar lightbox.

Also fixes pre-existing XSS in insertActionColumn (unescaped href/label)
and updates typography test for --text-page-title token change.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 19:43:03 +01:00
fs
6e35103bea fix: confirm button green 2026-03-24 19:20:23 +01:00
fs
91d8aa5055 fix: prevent false dirty indicator on read-only detail pages
Async component init (e.g. MultiSelect replacing <select> with hidden
inputs) mutated the DOM after the initial form state snapshot, causing
a phantom "unsaved fields" warning. Re-baseline the initial state on
structural DOM changes until the first user interaction.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 22:27:41 +01:00
fs
c7b8fd516a feat: extend module platform with UI slots, runtime components, CLI tooling and {{userId}} search support
Completes the generic module platform that enables modules to contribute
UI elements, runtime JS components, and search resources without any
core hardcoding.

New generic UI slot types:
- topbar.right_item: module-contributed topbar buttons
- layout.body_end_template: module-contributed dialog/overlay templates
- layout.head_style: module-contributed global CSS
- runtime.component: declarative JS component registration with phase ordering

New infrastructure:
- ModuleAutoloader: PSR-4 autoloading for module-local PHP classes
- ModuleRuntimePageBuilder: symlinks module pages into runtime directory
- ModuleRuntimeAssetPublisher: publishes module CSS/JS to web/modules/
- ModulePermissionSynchronizer: syncs module permissions to DB
- CLI scripts: module-runtime-sync, module-build, module-migrate,
  module-permissions-sync, module-assets-sync
- {{userId}} placeholder in SearchDataService for user-scoped search queries
- Component runtime with phased initialization (early/default/late)
- AppContainer.protectExistingBindings() to prevent module→core overwrites
- Architecture tests: ModuleStructureContractTest, CoreTemplateIsolationTest,
  FrontendComponentRuntimeContractTest, AppContainerIsolationContractTest

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 22:19:56 +01:00
fs
2b915f5a43 refactor: extract shared form utils, add aria-live regions and reduced-motion support
DRY duplicated helpers (escapeAttr, belongsToForm, isSubmitControl,
isEditableTarget) into web/js/core/app-form-utils.js and update 7
consumers. Add aria-live="polite" to flash messages, async messages,
and search results for screen reader announcements. Add
prefers-reduced-motion support to CSS tooltips.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 22:28:46 +01:00
fs
d9f07dcd63 fix: web/ quick wins — CSS cleanup, ARIA tabs, and file header comments
CSS:
- Remove duplicate li::before block in app-search.css
- Fix typo: search-reuslt → search-result in app-search.css
- Remove commented-out CSS rules in app-flash.css
- Add descriptive header comment to all 27 CSS component files

JS:
- Complete WAI-ARIA Tabs pattern: generate IDs, add aria-controls on
  tab buttons and aria-labelledby on tab panels (app-tabs.js)
- Add JSDoc header comments to ~33 JS files (core + components)
- Add explanatory block comment to app-boot.js (why classic IIFE)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 22:21:37 +01:00
fs
e1c211069e fix(session): preserve intended URL across session timeout with remember-me
Session timeout redirected to /de/login?return_to=... but the remember-me
cookie was not cleared by logoutDueToSessionTimeout(). On the next request,
autoLoginFromCookie() silently re-logged the user in, causing the MintyPHP
router to resolve the login route to pages/index().php (dashboard) instead
of the login action — the intended URL redirect logic never executed.

Fix: intercept ?return_to= immediately after successful auto-login in
index.php and redirect to the sanitized route path. Also harden the login
flow with hidden return_to form fields and POST body fallback for cases
without remember-me.

Additional improvements in this commit:
- Convert stored REQUEST_URI to router-compatible path (strip leading
  slash and locale prefix) via IntendedUrlService::toRoutePath()
- Consolidate duplicate CSRF data attributes into shared data-csrf-key
  and data-csrf-token on <html> element
- Add tenant branding (logo) to auth pages via appAuthLogoUrl() helper

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 18:28:13 +01:00
fs
277168f7e8 feat(admin): preserve list return target for back and close actions 2026-03-11 23:32:11 +01:00
fs
9a08f96c11 agent foundation 2026-03-06 00:44:52 +01:00
fs
b2dab5bd6c topbar anpassungen 2026-03-05 12:51:53 +01:00
fs
c5f657c8c8 listen ansichten verbessert 2026-03-05 11:17:42 +01:00
fs
4b31fc7664 Repo Interface für tests 2026-03-05 08:26:51 +01:00
fs
8f4dd5840d major update 2026-03-04 15:56:58 +01:00
fs
25370a1a55 add composer-unused, comprehensive docs, and project restructure
- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks
- Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists
- Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services
- Add Microsoft OIDC SSO, API token management, and user lifecycle features
- Add swagger-ui vendor integration and OpenAPI spec
- Add production Docker setup and bin/ scripts
- Update composer dependencies, config, templates, and frontend assets throughout

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 15:27:35 +01:00
fs
3eb9cc0ac4 big restructure 2026-02-11 19:28:12 +01:00
fs
cd59ccd99b baseline 2026-02-04 23:31:53 +01:00