Repository navigation
Conversation
volarname
force-pushed
the
feat/list-editors
branch
from
June 10, 2026 09:44
8a777ff to
de3e563
Compare
…temp ids, managed add/delete (item-factory/manage-delete), unsaved-section-label, renumberPositions util, row-key warnings
added 30 commits
September 23, 2026 17:22
…ers, collab takes io from the admin Docs - the vitepress site is gone (docs/, its scripts and devDependencies, i18nDocs.ts, the docs-props regions); what was still true lives as plain markdown: doc/guide (installation, i18n, styleguide), doc/editor (anzutap nodes, marks, extensions, scraper types), README-DEV.md for local development - the pages were checked against admin-cms and the other admins: pluralization, the admin i18n and vuetify setup, plugin options, global components, the eslint plugin, per-editor node availability, shortcuts, paste extensions and the embedExternal <-> scraper flow - README describes the versioning: Semantic Versioning with a few edge cases - CHANGELOG.md is an index; 2.0.0 is the first release with a changelog, its draft describes what the package contains instead of listing changes, and the per-topic unreleased notes are dropped Dependencies - every peer is required; unplugin is dropped (nothing imports it), sortablejs added (useSortable) - @sentry/vue, dayjs and @vueuse/integrations/useSortable were bundled into dist because the external list matched plain names only; they now resolve from the consumer - socket.io-client is no longer a peer: collab gets `io` through the plugin options (`collab.io`), so only an admin with collaboration installs it; CommonAdminCollabOptions is exported
Vite lib mode inlines assets, so the JPEG sat in dist/common-admin.js as 77 KB of base64. The SVG is drawn from the JPEG (same shapes, sampled colours; renders within antialiasing of the original at 1600x900, 320x180 and 160x90) and keeps width/height 1600x900, which VImg needs for the aspect ratio in ImageWidgetInner and ImageMediaWidgetInner.
…tup and the library's source maps
The six admins carried the same sentryVitePlugin block, and Sentry showed frames from the library
minified: Vite ignores sourceMappingURL in node_modules, so the admin maps ended in
dist/common-admin.js.
- commonAdminSourcemaps() loads the library dist files together with their maps, so the admin build
chains them and frames resolve to the library's .vue and .ts sources; only when the build emits
maps, the JS is unchanged
- anzuSentry({ project }) returns it plus the Sentry plugin: on when APP_DEPLOY_ENV and SENTRY_URL
are set, hidden maps, uploaded and deleted from the resolved build.outDir; a missing token, org or
project, or a failed upload, fails the build instead of a warning; other options override the
sentryVitePlugin defaults (e.g. a test release with finalize: false)
- @sentry/vite-plugin and vite are optional peers; without the plugin installed anzuSentry works
while Sentry is off and says what is missing once it is on
- node tests in src/test/vite run real Vite builds of a fixture (no network: upload skipped or
rejected by a local server)
- copy.sh fails fast, copies src/vite too and takes the target admins as arguments
…ts and sort its imports scripts/codemods/explicit-imports, run from here against an admin with the admin's own TypeScript, Vue compiler, unimport, oxlint and oxfmt: - run.mjs adds the imports: the TypeScript checker, without lib, module resolution or the generated auto-imports.d.ts, finds the names a file uses without binding them (value and type meaning apart), templates through _ctx.X of the compiled render function, template types through its TypeScript. Before and after it records what unimport injects, where every template reference is taken from, the runtime props and the import graph, and fails on anything left unexplained: residual injections, names unimport never injected, a template reference changing its target other than _ctx -> $setup for a name imported now, a prop gaining Boolean or Function, a new edge inside a cycle, a prop shadowed by an import. Exceptions from an allowlist in the admin; the manifest records what was added, the tool versions and this commit - sort.mjs runs oxlint --fix until it changes nothing (at most five passes), then oxfmt, then both in check mode - css-order.mjs compares the CSS of two builds when only the import order changed and lists the swapped rules that could decide the cascade - fixtures for the cases the plan lists (shadowing, the value and type namespaces, the readonly prop, template scopes, template casts, macros, the empty <script setup>, cycles, …); oxlint and eslint skip them
… library's declaration bundle A .d.ts with `declare global` anywhere in the repository reached the bundled common-admin.d.ts and renamed its types (Ref_2, IntegerId_2, useI18n_2). The fixtures keep it as auto-imports.d.ts.fixture and the test runner renames it in its copy.
…, and only swaps on the same box admin-cms showed what a per-file comparison misses: after its imports were sorted, rolldown packed the modules it loads at startup into fewer chunks (the same 2278 modules, 111 chunks instead of 143), so rules moved between the stylesheets index.html links while the page gets the same ones. - the stylesheets index.html links are one unit, in link order; lazily loaded ones stay per file - one entry per selector: the minifier merges neighbouring rules with equal declarations, and which rules neighbour depends on the order being compared - a scoped style's id is ignored in its keyframe names too - a swap only counts when both rules style the same box: not ::before against ::after, not img against div
…eleted The cleanup the labs merge prepared (commented out in src/lib.ts, the admins built and tested against that state): with the admins now on explicit imports, their six builds and test suites confirm nothing they use is gone. - src/lib.ts: the commented-out imports, exports, aliases and their JSDoc deleted (the section headings stay); SortableNested and SortableNestedItem are declared in listEditorTypes, the only link from live code to the old sortable - 62 files deleted: the old lib pairs of the labs components (filters, datatable pagination and ordering, remote autocompletes, subject select, sortable), the old api helpers, filter helpers and query builder, ACropperjs (cropper.js v1), the dead list editor composables, and files nothing used any more (KeywordCreateButton, useDirtyBaseline, locales/xx.ts, Image, AssetSlot) - dead symbols deleted where their file stays (CurrentUserType, the purge-room event bus, CollabRouteMeta, UseListEditorOptions, GrantDefault, LogLevelDefault, ApiResponseList, EnableDisable, the *Default constants of AssetFile and DamConfig, ObjectPaths, Prettify, arrayToString, timestampCurrent, yearNow, objectGetValues, stringTrimLength, stringNormalizeForSlotName, stringUrlTemplateReplaceVueRouter) and the imports they left unused - the eslint rule anzu/no-fatal-error-axios-check goes with the old helpers whose error shape it checked; recommended() ignores an unknown option - tests: the cropper suites drive ACropper only, the query builder contract keeps the labs half, the add-after cases run on useListEditorController, the tests of deleted functions are deleted; cropperjs (v1) leaves the devDependencies - playground: the cropper view shows v2 only, the sortable view is gone (the list editor views replace it) - the browser vitest no longer collects scripts/ (the codemod fixtures hold a *.test.ts) - doc/2.0.0-UPRATOVANIE.md, the working note, is deleted now that it is done yarn ci, yarn build, yarn test:run (browser 1463, node 47).
… the public entry Preparing per-module output with `sideEffects`, where a consumer's bundler keeps only what is used: - ACropper calls `$define()` for the seven cropper.js elements it builds. cropper.js registers them as a side effect of loading its entry; once the library ships per module and says it has no side effects, that module is dropped whenever only the element classes are used, and the cropper would build unregistered elements. `$define` is a no-op for a registered element - jobPriority and AssetImagePreview imported `objectGetValueByPath` and `isUndefined` from `@/lib`, a cycle through the entry that would put every export into the graph of those modules; they import from `@/utils/object` and `@/utils/common` now, and eslint forbids `@/lib` (or a relative path to it) inside `src` yarn ci; the cropper suites twice (139).
…dules, the bookmark dialog loads its editor on demand
Two edges that pulled heavy modules into every admin's startup once the library ships per module:
- AnzuSystemsCommonAdmin imported initCommonAdmin{Image,CoreDam,Collab}Options from the DAM, image
and collab composables, and with them the image API and their other imports. The option refs and
the init functions live in src/plugins/pluginOptions.ts now; the area modules read the refs from
there and still re-export their init function. Same behaviour: one ref per option, the image and
coreDam composables throw until configured, collab starts disabled -- pinned by
pluginOptions.test.ts, written against the old wiring first and green on both
- FilterBookmarkDialog imported ASortableListEditor (and sortablejs under it) statically, so every list
page with the bookmark button carried it. The manage tab loads it on its first visit
(listEditorLoader, with a 15 s timeout), on its own track next to the bookmark fetch: a spinner
while it comes, an error with a retry button when it does not, the save disabled until it is
there. The template ref reaches the editor once it is mounted; everything that talks to it already
tolerated its absence. New cases: loaded on the first visit and not with the dialog, a failed load
and the retry, the fetched list kept across a failed load, a second dialog after the first closed
yarn ci, yarn test:run (browser 1477, node 47).
…ts and exports its entry points explicitly - vite.config.lib.mts: `preserveModules` with `src` as the root, so dist/ mirrors src/; bundled dependencies go to dist/vendor/ (yarn pack leaves out every node_modules directory, a nested one too), their names built by hand while the library's own modules keep `[name]`, which rolldown sanitizes (no `?`, `&` or `=` in any path); `rollupOptions` becomes `rolldownOptions` - a pre plugin resolves the locale files up front, sorted: @intlify/unplugin-vue-i18n numbers its virtual modules in resolve order, and per module that number is a file name, so two builds of one commit differed in 96 files. Two builds, one of them on a single CPU, are now identical (1593 files) - package.json: `"sideEffects": ["**/*.css"]`. It applies to this build too: compared with a build without it, it drops 12 bare imports kept only for their order, each of a module with no top-level effect (metadataToImageMap, useNestedListEditor, logFilter, logApi twice, types/coreDam/Asset twice, ImageWidgetInner, damAssetApi, useNestedListEditor again, utils/common). The load-time effects left in the library are module state (theme, language, pinia stores, caches), HMR guards and dayjs.extend in the three modules that use the plugins themselves - exports: `.`, `./styles`, `./eslint`, `./oxlint`, `./vite`, `./package.json`, types first; the `./*` wildcard goes. The admins use `.`, `./styles`, `./eslint` and `./vite` - common-admin.d.ts is byte for byte the one the single-file build emits; the packed tarball holds the same 1593 dist files as the local build - changelog: the packaging of 2.0.0 yarn ci, yarn test:run (after the previous commit, unchanged sources), yarn pack.
The region editor (DamAssetImageRoiSelect with cropper.js) loads when a detail dialog of the upload queue first shows it, through DamAssetImageRoiSelectLazy and damAssetImageRoiSelectLoader (15 s timeout, a retry). rusha, which hashes an upload, loads when a file starts uploading and before its asset is created, also with a 15 s timeout. A page that only shows the upload queue no longer carries either. The item is marked uploading before that first await, as it was before: the queue restarts every item it still sees waiting, and it looks again after each file it adds. A stop while rusha loads or while the asset is created sends no chunk. Tests: DamAssetImageRoiSelectLazy, uploadStopWhileHashLoads (each guard fails the test without it) and uploadQueueStartsEachFileOnce (five starts instead of two without the fix). Step 3 criterion: admin-ugc's DAM median route -10.7 % (was -7.7 %); all six admins pass.
… build info copy.sh refuses to copy when dist/ lacks common-admin.js, .d.ts or .css (a build that did not finish) before it deletes the admins' copies. It also removes node_modules/.cache/tsc in each admin: tsc --build does not look at node_modules, so a warm vue-tsc would call the admin up to date against the old declarations. README-DEV describes both.
…slint and stylelint without a cache tsBuildInfoFile moves to node_modules/.cache/tsc (all tsconfigs are noEmit). eslint and stylelint lose --cache: eslint reuses a file's result without tracking the files it depends on, and stylelint hashes only the first configuration it resolves (.vue and .scss resolve differently), so a warm run could pass what a cold one reports. The Lint job restores node_modules/.cache after yarn install (actions/cache/restore@v6) and saves it after a passing yarn ci, before the audit (actions/cache/save@v6). The key covers runner, Node version, yarn.lock and tsconfig*.json (vue-tsc's build info does not notice a vueCompilerOptions change) plus the run. Verified: yarn ci; only tsc in node_modules/.cache. The workflow is YAML-checked, it has not run yet.
release.config.json, the release workflow as the stub of the tool (its action builds, checks and publishes a tag the tool created), the release:* scripts, and the changelog in the format of the tool: doc/changelog/2.0.0.md and doc/changelog/template.md with the header "{version} — unreleased". The README says how releases are made.
…d tests Fixes found by the 2.0.0 review (upload queue, image widgets, filters and lists, list editors, forms, auth and collaboration, utils, styles, fonts), and what the six admins carried as copies, now in the library: - token refresh, start-up (startWithEnvConfig), reload on a new version - api clients (defineApiClient), app shell (ALayoutSwitch, ALayoutLoader, AActionbar, AActionbarTarget), createAnzuVuetify - createRemoteAutocomplete / createFilterRemoteAutocomplete with props, filterFromProps and scope - ./testing: the admins' guard tests (routes, close buttons, route history, sortable lists and their unsaved registration, alert host, CSS layer order) - ./eslint admin preset, ./vite dev watch into an admin - the stylesheet in the anzu-common cascade layer, Vuetify's sub-layer order - noUncheckedIndexedAccess on for the library Breaking changes and the migration: doc/changelog/2.0.0.md.
AuthUnavailableError, SessionExpiredError and isInCauseChain move out of refreshSession into model/error, next to the library's other errors: alerts and apiErrors imported the refresh only for them, and that closed an import cycle through eight parts of the library. SortOrder and SortOrderType move out of datatableColumns into labs/api/SortOrder: the list helpers are query primitives and used nothing else of the datatable. Exports, behaviour and the classes themselves are unchanged. Groundwork for the domain layout (E1), which moves files only.
src/ by domain, as in the admins: src/domains/<domain>/[<entity>/]<kind>/, src/shared/, src/plugins/; labs/ is gone. Tests move into __tests__ next to the code they test; src/test keeps the tests of the library as a whole and those of src/eslint and src/vite, which ship as source. Renames and rewritten paths only, plus the tsconfig and eslint globs for nested __tests__, two test globs, the api lint rules' path of useApiRequest, the sort order of one listed import cycle and doc prose. The import graph is the graph before, renamed edge by edge; the build exports the same names, modules and types. A branch from before: git merge -X find-renames=30% (three short files that are mostly imports are below git's default 50 % similarity).
The Pinia stores are commonAdmin… (the admins' own common… stores would share state with them), the browser keys of the users and permission groups lists common…: both lists start once with the default filter and columns. Comments and test names without labs; the api lint rules have a test that they see the library's own useApiRequest. doc/API-HELPERY-MIGRACIA.md, the analysis of the labs api migration, leaves the repository.
…fter an immediate delete - useFormatAndSizeCheck compares `accept` and `maxSizes` keys lowercased and trimmed (`.JPG`, `'image/png, .jpg'`); an uppercase key never matched. - useLoginStatus keeps each call's verdict: a later navigation reset it before the start-up read it after its awaits. - List editors: a row deleted in `immediate` mode leaves the saved state too (in the nested editor with its saved subtree), so `reset()` no longer brings it back. - The nested editor's children toggle is named Expand/Collapse, with `aria-expanded`. - The plugin warns when it is installed without `i18n`. - ./testing: describeDeclaredDependencies fails on an import of a package the admin's package.json does not declare, which only a hoisting node_modules resolves. The library checks itself with it: `@typescript-eslint/parser`, which the eslint rule tests import, is now a devDependency.
…says what a misread costs The scan took `export default /…/` for a division. Its comment said a division misread as a regex drops nothing; it copies to the next `/` on that line and reads on from there. Test with a regex after `default` that, misread, hides the import behind it.
…lopment warnings that reach the admins - createRefreshSession watches the JWT cookie for up to a second after a 400 before the session counts as gone: the other tab's answer, with the rotated cookie, can arrive after this tab's. - The plugin registers AChipNoLink, the component; `commonAliases` no longer maps it to a plain VChip. - <Acl> warns in development, once per permission, when its check throws. isDevelopment() reads process.env.NODE_ENV, which the admin's build replaces; import.meta.env.DEV is fixed by the library's own build, so ALogDatatable's warning never showed in an admin. A test keeps import.meta.env out of src. - AFormRemoteSwitch and AFormRemoteCheckbox with `hideLabel` take their accessible name from the label. - The test setup builds Vuetify with the library's aliases, so ABtn* are real buttons in the tests.
…er restarts that keep the old one - AImageMediaWidget releases its collab field with the image and the media (ImageMediaCollabValue), and with what it just assigned: under a v-model parent an assigned model shows only after the parent renders, so a release that read it back sent the previous image. - A readonly ADatetimePicker / AFormDatetimePicker offers neither the calendar nor clearing. The text fields and AFormSwitch declare `readonly`, left to a readonly VForm when not set; AFormTextField declares and forwards `modelModifiers`. AFormValueObjectOptionsSelect shows `help` and applies its `hideDetails`. - useRouteHistory's blacklist takes route names (RouteRecordName). - createRemoteAutocomplete types the autocomplete's events on its result. - commonAdminDevWatch hands a restart a copy of the server's environments and empties it once the new server stands: Vite 8.3 keeps the previous server's environments in the new one's closure (vitejs/vite#23493, fix in PR #23499). TODO to drop it once Vite ships the fix. - describeDeclaredDependencies reads module augmentations (`declare module '…'`), and the guard reads `.d.ts` files. - The asset picker tile's title has a data-cy for the admins' e2e. - Tests for each.
…odel with permissions only - ADamUserRemoteAutocomplete, the form field to ADamUserFilterRemoteAutocomplete: picks a DAM user in an admin that is not DAM, through the DAM client of the `coreDam` plugin options (`configName`) or `client`. - AUserCopyPermissionsDialog copies into any model with roles, permission groups and permissions, not only a whole AnzuUser: a wizard holds a system's permissions without the rest of an account. - The image widget reloads the media it just assigned, not the model it was assigned to. - Changelog: the widget's collab value is a change an admin that applies room data itself has to follow. - Tests for each.
…op while another editor holds it - One release per lock taken, in both collab image widgets: the explicit release after a remove or a confirm and the menu/dialog-close watcher each released, the server refused the second, and the refusal read as the lock still held. In an inactive room every release still writes the value for the editors who join. The image confirm releases before its reload, so what goes out is what was just assigned. - A new lock request resets the "really locked" state, so a drop waits for the answer to its own request. - A drop is refused, as a click on the dropzone is, while another editor holds the field. - The DAM region editor test waits until picture and selection hold still, not a fixed pause: it flaked once in the full suite. - Tests for each.
… ask again for a refused one - A pick from DAM counts as an open dialog while the asset is fetched or copied into the licence: the picker closes first, and the close gave the lock up with the old value, so the pick never reached the other editors. A pick that ends without a dialog still releases. - A lock not yet confirmed is asked for again by the next drop and when the menu opens: a refused request left every later drop waiting 5 s for a lock never granted. Never while a request is out, and never from the click that also closes the menu, which raced its release on the server. A failed answer keeps the lock counted: a timed-out request answers the same, and the server may have granted it, so it is still released. - Tests for each.
…em bar's retries, the DAM socket teardown - The upload queue stops an item it removes as a stopped upload is: one still sending aborts its chunk instead of finishing unseen, being polled afterwards and uncounted against the parallel limit; one whose status fallback waits for the asset polls no more (it went on for the tries left, holding the file). - An upload stopped during its finish request stays stopped and is not polled. - ASystemBar clears the pending retry before it schedules one: a return to the window while a retry was pending started a second chain, and the unmount cleared only the last timer. - destroyDamNotifications is exported again (in 1.49.0, dropped from 2.0 with the commented-out exports), and a handle disposed directly is forgotten, so the next initDamNotifications() returns one that opens. - Changelog: a stop between or during chunks keeps the upload from finishing, it never kept the asset from being created. - Tests for each.
…image widgets ask again after a lost connection - A lock held when the other editor leaves is released on the server too, for every collab field and the useCollabAnyDataChange locks, also one whose request timed out (the server may grant it late and tells only the others): it stayed, and whoever came back found the field locked. The value still goes to the buffer. - The image widgets release a lock taken in an active room after the room turned inactive. After a lost connection they ask for it again once the room is back, and a menu or dialog opened while alone asks for it when another editor arrives. - A drop whose wait for the lock ran out releases a lock the server may have granted late, when no other drop, menu or dialog waits for or holds it. While a request is out, the answer to an earlier release leaves the lock state alone: a refused one read as the lock held let a drop upload before its own answer. - A DAM pick that ends early leaves the metadata dialog not loading. - AFileInputDialog.activate() opens the dialog and the file choice: it reached for a ref that was never set. - Tests for each.
…irmed, the image widgets ask again for a refused lock on arrival - A lock request that timed out stays counted as possibly held until a release of it is confirmed: a retry can be refused while the slow request still holds the field on the server, which grants it after, and a release that timed out may not have reached it. Cleared on any acquire answer and before every release, the claim was lost and a release in an inactive room skipped the lock the server still held. - When another editor arrives, an image widget with its menu or a dialog open asks again for a lock that was refused or went unanswered, not only for one never asked for. - Tests for both composables, a dialog open on arrival and while a drop waits, a refused lock asked for again; the widget tests reset the shared upload queue dialog, so a failed try no longer lets its retry pass.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.