feat: Migrate to Vue Router and refactor views to @conduction/nextcloud-vue - #1
Merged
Conversation
Replace existing license (Apache-2.0/AGPL) with EUPL-1.2 across all metadata files: LICENSE, appinfo/info.xml, composer.json, package.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…orkflow Add Conduction coding standard with custom sniffs, PHPMD mess detection, ESLint with Nextcloud config, and stylelint. Add GitHub Actions workflow for PR quality checks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add project architecture docs, feature specs, and OpenSpec change tracking for structured development workflow. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Apply Conduction PHPCS standard. Add deep link registration listener, register configuration, and admin settings infrastructure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add dashboard widgets, My Work view, case create dialog, case detail components, task management views, and admin settings with case type configuration. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only allow PRs from 'development' or 'hotfix/*' branches to merge into main. Other source branches will be blocked by a required status check. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enforce branching strategy: main only from beta, beta only from development, development only from feature/*. Hotfix/* bypasses all restrictions. Add beta to quality check triggers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document the promotion-based branching model (feature→development→beta→main), hotfix policy, required quality checks, and local development workflow with a mermaid flow diagram. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds NcAppSettingsDialog-based user settings accessible from sidebar Configuration menu. Consolidates UserPreferencesController into SettingsController. Backend uses OCP\IConfig for per-user storage. Updates register schema JSON and repair step. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New modal dialog for creating tasks from list view. Dashboard KPI card hover fixes. Case and task list views updated with consistent filtering. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rary AdminRoot uses CnSettingsSection for Case Type Management section. Settings wraps form in CnSettingsSection with doc-url and loading state. Webpack dedup aliases use $ suffix for exact-match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…webpack alias Makes the shared library work in both monorepo dev (local source alias) and CI/production builds (npm package from git). The alias only activates when ../nextcloud-vue/src exists. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replaces github:ConductionNL/nextcloud-vue#main with ^0.1.0-beta.1 from npm registry. Faster installs, no git clone + build step. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Nextcloud App Store schema does not accept EUPL-1.2 as a valid licence value, causing all release uploads to fail with HTTP 400. Revert to 'agpl' which is in the accepted set. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add vimeo/psalm ^5.26 + psalm.xml config - Add phpstan/phpstan ^1.10 + phpstan.neon config - Add nextcloud/coding-standard, phpcsstandards/phpcsextra - Add roave/security-advisories, edgedesign/phpqa - Add psalm, phpstan, phpmetrics:violations, phpcs:output, phpqa scripts - Fix phpmetrics:violations flag to --violations-xml (matching OpenRegister) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e coverage Replaces the one-liner README with a comprehensive document covering: - Logo and CI badges header - Screenshots table (dashboard, cases, admin) - Detailed feature sections organized by category - Mermaid architecture diagram - Data model table with CMMN 1.1 and ZGW API mappings - Directory structure - Requirements, installation, and development guide - Tech stack and standards/compliance Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tcloud-vue Replaces manual currentView/currentRoute navigation with vue-router. App.vue now renders <router-view /> and mounts CnIndexSidebar globally. CaseList and TaskList are refactored to use CnIndexPage with schema- driven columns and built-in CRUD dialogs. Adds src/router/ for route definitions. Updates procest_register.json schema and bumps dependencies. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rubenvdlinde
added a commit
that referenced
this pull request
Mar 22, 2026
…rements) Evidence-backed proposals from 39,600 tenders across 8 EU countries: 1. workflow-engine-enhancement (534 tenders) — foundational, prerequisites for 2-4 2. vth-workflow-configuration (436 tenders) — VTH domain config, depends on #1 3. bezwaar-beroep-workflow (280 tenders) — AWB-compliant, depends on #1 4. besluitvorming-workflow (126 tenders) — decision process, depends on #1 5. signalering-widgets (160 tenders) — dashboard alerts 6. doorlooptijd-dashboard (350 tenders) — SLA analytics 7. deelzaak-support (245 tenders) — sub-case hierarchy 8. gis-integration (300 tenders) — map views, PDOK, WMS/WFS
This was referenced Aug 11, 2026
rubenvdlinde
added a commit
that referenced
this pull request
Aug 11, 2026
) `DsoIntakeService` carried two implementations of DSO intake. The live webhook path (`processAanvraag`, POST /api/vth/dso/intake) did the extract → build → save → save-properties inline, while an extracted `map()` + `createCase()` pair sat next to it with zero callers — an abandoned "make intake testable" refactor. `createCase()` was not merely unreachable, it had never run. It called OpenRegister's ObjectService positionally: saveObject($register, $caseSchema, $caseData) against the real signature saveObject(array|ObjectEntity $object, ?array $extend = [], $register = null, $schema = null, ...) so the schema slug landed in `?array $extend` and the register slug in `array|ObjectEntity $object` — a TypeError on the first call. The same bug was in its case-property loop. This wires the orphan instead of deleting it: - `processAanvraag()` now delegates to `map()` + `createCase()`, so there is ONE implementation of the intake write rather than two. - `createCase()` passes register/schema by NAME, fixing the latent TypeError, and reuses the existing `storeCaseProperties()` helper (which already had the argument order right) for the property rows. - `createCase()` adopts the live path's log line, so the message the webhook has always emitted is preserved. Characterization tests were written FIRST, against the pre-refactor code, and pin the observable behaviour of the live path: the exact saveObject call sequence including which parameter each named argument binds to, the case-property rows written vs skipped, and the byte shape of the JSON the Omgevingsloket receives back. They passed before the refactor and pass after it, unedited. The ObjectService test double declares OpenRegister's real parameter order, so the argument-order assertions are not vacuous: reverting to the positional call makes 12 of the 15 tests fail with "saveObject(): Argument #1 ($object) must be of type array, string given". Verification (hydra-gates @ ConductionNL/.github b8c7ead, 66 gates): - gate-57 orphaned-write-capability: 16 → 15; the only removed finding is DsoIntakeService::createCase. - gate-25 contract-coverage: 126 → 126, findings log byte-identical. - Failing-gate ID set identical before and after — no new gate fails. - composer phpstan: no errors. - composer phpcs: 1 error + 501 warnings in 219 files, identical to origin/development; the changed file carries the same 2 warnings. - vendor/bin/phpunit: 1761 tests green (1746 baseline + 15 new), 5 skipped. Behaviour note: on a MALFORMED payload with OpenRegister unavailable, the mapping now runs before the config guards, so such a request surfaces the mapping error rather than "OpenRegister is not available". Both are a 500 from the webhook and neither message is part of the response contract.
rubenvdlinde
added a commit
that referenced
this pull request
Aug 15, 2026
…ferent class"
The reconcile pass removed VALID arguments. PHPUnit, after it:
Error: DsoObjectRepository::__construct(): Argument #1 ($settingsService) not passed
Error: ZgwRulesBase::__construct(): Argument #1 ($logger) not passed
Error: Too few arguments to ProcestCaseReader::__construct(), 0 passed
It was written to fix ONE real problem — two classes sharing a file stem, where
`new ChecklistService()` was given three arguments belonging to
lib/Service/Inspection/ChecklistService.php. That problem is real and is fixed
by hand in the next commit.
The pass itself judged every construction in the file, and where its constructor
parse came back empty it treated every named argument as unknown and deleted it.
A tool that removes code needs to be certain, not merely unable to confirm;
reverting is cheaper than making it certain, since exactly one call site
actually needed changing.
rubenvdlinde
added a commit
that referenced
this pull request
Aug 15, 2026
…#847) * refactor(deps): inject OpenRegister instead of looking it up (ADR-083) 2 file(s) reached OpenRegister through $this->container->get(...) on an UNCONDITIONAL path — no availability check, no degrading catch. The dependency was announced nowhere: not in the constructor, not in the use block, not in any type. It appeared mid-method, as a string. Now constructor-injected and typed, so the dependency is visible to a reader and to tooling. Behaviour is unchanged: the same object, from the same container, resolved at construction instead of at first use. ContainerInterface is dropped only where nothing else used it. Deliberately NOT converted, because they are correct as written (ADR-083 rule 1's exception): lookups behind isInstalled()/getInstalledApps(), and lookups whose catch degrades rather than rethrows. Verified per file: php -l clean, and gate-66's lookup check reports zero remaining findings for each file changed. gate-66 for this app: 3 -> 1. * style: put the injected parameter on its own line The transformer appended the new promoted parameter AFTER the whitespace-only line preceding the closing paren, producing private readonly ObjectService $objectService,) { php -l accepts that; phpcs does not, and it reads badly. Fixed here and in the transformer, which now backs up over trailing whitespace before inserting when the constructor has no defaulted parameters to sit in front of. No behavioural change — parameter list is identical. * refactor(deps): type-hint OpenRegister's published contract (ADR-084) Five services take OCA\OpenRegister\Contract\ObjectServiceInterface instead of the concrete class, bound in the composition root, with hydra-gates bumped to v1.8.0 so composer installs the interface into vendor/. This is what makes the ADR-083 conversion mockable. A leaf app cannot load a class from another Nextcloud app, so a typed constructor parameter had no satisfiable double: TypeError: __construct(): Argument #N ($objectService) must be of type OCA\OpenRegister\Service\ObjectService, class@anonymous given The 199 files that name ObjectService only as a CONTAINER KEY are untouched. Those are availability-guarded lookups — the ADR-083 rule-1 exception — and the string must go on naming the concrete service, because that is the key the alias resolves TO. Rewriting it would have made the container look up something nobody registered. Two of these five files were nearly missed. The first transformer masked string literals with a regex, and in DsoCaseService the comment `// King's Day.` opened a string that did not close until `date('N')` 240 lines later — so every type position between them looked like it was inside a string and the file was silently skipped. A skipped file is indistinguishable from a clean one, which is why it took a count to notice: 3 converted where 5 were due. The transformer now takes its comment and string ranges from PHP's own token_get_all(), and reports every file it declines to convert together with the reason. * fix(adr-084): complete the conversion the first transformer under-did The first pass through this app used a transformer with three defects, each of which failed SILENTLY -- a skipped file is indistinguishable from a clean one. 1. It masked string literals with a REGEX. An apostrophe in a comment (`// King's Day.`) opened a string that did not close for 240 lines, so every type position between them looked quoted and the file was skipped. Now the comment and string ranges come from PHP's own token_get_all(). 2. It compared PHP's BYTE offsets against Python's CHARACTER indices. One file differed by 94 -- em dashes in prose comments -- so spans after the first non-ASCII byte were misaligned and a docblock was judged "not in a comment". Everything is handled as bytes now. 3. It missed short-form RETURN types (`): ?ObjectService`), which neither the parameter nor the fully-qualified pattern matched. And it dropped the concrete import even where `ObjectService::class` or `instanceof ObjectService` still needed it. That one is not merely incomplete, it is silent damage: `::class` does not require the class to exist, so the lookup would have resolved to this app's own namespace. An invariant check now enforces the rule -- a file may import the contract, or both, but never the contract alone while still naming bare ObjectService -- and reports 0 for every app in this rollout. * test: construct the two services with the contract they now require ADR-083 added a fifth constructor parameter and the tests still passed four: ArgumentCountError: Too few arguments to DsoCaseService::__construct(), 4 passed and exactly 5 expected Both sites use named arguments, so each is one line: an ObjectServiceInterface mock. That clears 6 of the 8 PHPUnit errors on this branch. NOT fixed here, deliberately. testCreateZaakFromVergunningaanvraagCallsObjectService builds its double from a LOCAL interface declared in this test file, DsoCaseObjectServiceStub, whose own docblock describes exactly the problem ADR-084 solves -- a \stdClass mock generates positional-only signatures and dies on "Unknown named parameter", so somebody hand-rolled a typed interface to get named arguments working. It is an eleventh double, and being an interface rather than a class it was missed by the fleet count of ten. Swapping it for the contract is not mechanical: it stubs find() to return an ARRAY, while the contract returns ?ObjectEntityInterface. That is the same shape as openbuild's stub failure, but the fix there was to make the stub satisfy the contract; here the test is asserting on a raw array it never had to justify. It needs a decision about what the test should actually assert, not a rushed signature change. * fix: saveObject() returns an entity, and two methods were returning it as array The last PHPUnit error on this branch was not a test problem. It was the test faithfully modelling a production defect. `createZaakFromVergunningaanvraag(): array` did $created = $objectService->saveObject(...); return $created; and `ObjectServiceInterface::saveObject()` returns an ObjectEntityInterface. That worked only while the service was reached through an untyped container lookup, which returned whatever it returned and told nobody. The test's local stub returned raw arrays because that is what production expected. Fixed on the production side, using the shape this app already had: a saveObjectAsArray() helper next to findObjectAsArray(), same array-or- jsonSerialize() normalisation, applied at the two sites that RETURN the result. The third (syncPermitApplicationStatus) discards it and is unchanged. The test now mocks the contract and returns what the contract promises — entities whose jsonSerialize() carries the payload — and rebuilds the service with that double, because the container path setUp() configured is dead now that the dependency is injected. DsoCaseObjectServiceStub is deleted. It was an ELEVENTH hand-rolled double, and being an interface rather than a class it was missed by the fleet count of ten. Its own docblock stated the problem ADR-084 exists to solve: "a \stdClass-based mock generates positional-only signatures and fails at call time with Unknown named parameter; this typed interface lets PHPUnit generate a mock whose method signatures accept the named arguments". Someone hand-rolled a contract to make mocking work. Now there is a published one. * fix: the contract lives in Contract\, not Service\ phpstan caught a defect in the rollout transformer: PHPDoc tag @var for property $objectService with type OCA\OpenRegister\Service\ObjectServiceInterface is not subtype of native type OCA\OpenRegister\Contract\ObjectServiceInterface The docblock rewrite matched `@var \OCA\OpenRegister\Service\ObjectService` and appended `Interface` to the CLASS name while leaving the NAMESPACE alone, so the declared type named a class that does not exist. The native type next to it was correct, which is why only phpstan noticed — PHP itself never reads the docblock, and the tests pass either way. That is the fifth silent failure from this transformer, and the same shape as the others: it produced plausible output that no runtime check disagreed with. * ci: adopt development's Code Quality workflow — the branch had the pre-fix one These branches were cut from ADR-083 branches predating the 2026-08-14 correction, so they carry an older code-quality.yml whose push trigger has no refactor/** — which is this branch's prefix. development's version says why that matters: An ALLOW-LIST of branch prefixes is a gate with a hole in it, and the hole is SILENT: a branch matching nothing gets no CI at all, and its last visible status is whatever it inherited — indistinguishable, on every dashboard, from a branch that passed. Observed here: softwarecatalog#519 settled at FOUR checks (CodeQL and Analyze only) and read as green, having previously reported 43. shillinq#556 did the same at three, which is shillinq#557. Takes merge-hygiene.yml with it, the companion added in the same change, which runs the fast structural checks on ** so an unlisted prefix is not completely unguarded. This restores coverage via the PUSH path. It does not explain why the pull_request runs stopped, which is tracked separately. * test: seed the Samenwerkverzoek doubles from the contract, not a local stub procest's PHPUnit went 8 errors -> 3 after the arity fix, and all three were the same thing: "Zaak not found", "Samenwerkverzoek not found". A bare createMock(ObjectServiceInterface::class) returns null from find(), so the service correctly concluded the object did not exist. The seeding was there — it just went to the wrong place. The tests configured a SamenwerkObjectServiceStub mock and handed it over through the CONTAINER, and the container path is dead now that the dependency is injected. So the service was built with setUp()'s empty double while a fully-seeded one sat unused. Two changes per test: mock the contract, and rebuild the service with that double instead of relying on the container. find() and saveObject() now return ENTITIES via a small entity() helper, because that is what the contract promises and what the service normalises with jsonSerialize(). The old stub returned bare arrays — which the untyped container lookup allowed, and which is the same mis-shaped double this ADR keeps turning up. * test: complete the ADR-083 constructor changes and make the stubs satisfy the contract Three distinct pre-existing defects, all of which only became visible once the tests could actually construct their subjects. 1. ARITY, completely this time. The first pass added `objectService` only, because that is the parameter ADR-084 was about. ADR-083 added others in the same commit — softwarecatalog's ContactpersonenController gained THREE (objectService, magicMapper, organisationService) — so a call could be fixed for one and still be short by two. Every required parameter is now supplied, by NAME so it fills the right slot regardless of the existing arguments. 2. IMPORTS for the types those arguments name. `createMock(MagicMapper::class)` without a `use` resolves the short name against the TEST's own namespace, and `::class` does not require the class to exist — so it silently mocks a class nobody declared. Same trap as the container-key strings in lib/. 3. The ObjectEntity STUB now implements ObjectEntityInterface. Once ObjectServiceInterface is mocked its return types are enforced: Method find may not return value of type MockObject_ObjectEntity, its declared return type is "?OCA\OpenRegister\Contract\ObjectEntityInterface" A hand-rolled double that does not declare the interface cannot be handed back. This is ADR-084's argument arriving in the tests: ten apps had such a double, and none of them was checked against anything until now. softwarecatalog also gains a MagicMapper stub, because ADR-083 injected OpenRegister's MagicMapper into a controller and this app has no way to load it. That stub is debt of exactly the kind ADR-084 removed for ObjectService — noted in the file so it stays visible rather than becoming furniture. php -l on every touched file, reverted on failure. * refactor: drop the dead catch ADR-083 left behind phpstan, on this branch: Dead catch - Throwable is never thrown in the try block. getObjectService() used to resolve the service from the container, which could fail, so it wrapped the call and rethrew a RuntimeException. ADR-083 made the dependency injected, and the body became `return $this->objectService;` — a property read, which throws nothing. The catch survived the conversion and was unreachable. Removing it is not a loss of safety: absence is now a CONSTRUCTION failure on the route that needed the data, which is precisely what ADR-083 rule 1 asks for, rather than a RuntimeException raised deep inside a call. * fix(tests): remove constructor arguments that belong to a different class The arity fixer keyed constructors by FILE STEM, and two classes with the same stem in different namespaces collide. procest has lib/Service/ChecklistService.php no constructor arguments lib/Service/Inspection/ChecklistService.php three so a correct `new ChecklistService()` was given three arguments belonging to the other class: Error: Unknown named parameter $settingsService Constructions are now resolved through the FILE'S OWN `use` imports to a fully-qualified name before their arguments are judged. The reconcile pass was itself wrong on its first run, in a way worth recording: its parameter parser only accepted types beginning with a capital, so `string $appName` on every Nextcloud controller was invisible and a valid `appName:` argument looked like one the constructor did not have. It removed 33 files' worth of arguments in procest; with scalar types accepted it removes 8. The tell was reading a diff that deleted `appName: 'procest'` — a line no plausible fix would touch. php -l on every touched file, reverted on failure. * chore(phpmd): record why DsoCaseService is one collaborator over ADR-083 replaced a lazy container lookup with a typed ObjectServiceInterface dependency — the point of the ADR, since the dependency becomes visible to readers and to tooling. That took the class to 13 collaborators, one over phpmd's threshold. The container cannot simply go: IGroupManager is still resolved through it. Swapping one for the other would leave the count unchanged. Suppressed with the reason attached rather than silently, and consistent with this app's own convention — 29 classes here already carry it. * fix: repair references to the local $objectService ADR-083 deleted phpmd, on this branch: UndefinedVariable $objectService ADR-083 replaced $objectService = $this->container->get('OCA\OpenRegister\Service\ObjectService'); with an injected property and rewrote most usages to $this->objectService — but not all. What remained read a local that no longer exists. In PHP that is not a parse error and not a test failure unless the line executes; it is null at runtime, and the call it feeds gets null instead of the service. Rewritten only where the enclosing function has no assignment to that local AND does not take it as a PARAMETER — several helpers legitimately receive it, e.g. CreditLimitGuard::sumOutstandingCents(object $objectService, ...), and those are untouched. php -l on every touched file, reverted on failure. * Revert "fix(tests): remove constructor arguments that belong to a different class" The reconcile pass removed VALID arguments. PHPUnit, after it: Error: DsoObjectRepository::__construct(): Argument #1 ($settingsService) not passed Error: ZgwRulesBase::__construct(): Argument #1 ($logger) not passed Error: Too few arguments to ProcestCaseReader::__construct(), 0 passed It was written to fix ONE real problem — two classes sharing a file stem, where `new ChecklistService()` was given three arguments belonging to lib/Service/Inspection/ChecklistService.php. That problem is real and is fixed by hand in the next commit. The pass itself judged every construction in the file, and where its constructor parse came back empty it treated every named argument as unknown and deleted it. A tool that removes code needs to be certain, not merely unable to confirm; reverting is cheaper than making it certain, since exactly one call site actually needed changing. * fix(tests): ChecklistService takes no constructor arguments OCA\Procest\Service\ChecklistService has an empty constructor. The three arguments passed here belong to OCA\Procest\Service\Inspection\ChecklistService, a different class with the same FILE NAME — which is what an earlier fixer keyed constructors by, and how they arrived: Error: Unknown named parameter $settingsService This is the one call site that genuinely needed changing; the sweep written to find it removed valid arguments elsewhere and has been reverted. * fix(tests): drop constructor arguments belonging to a same-named class Several classes here share a FILE NAME with another in a different namespace — lib/Service/ChecklistService.php and lib/Service/Inspection/ChecklistService.php, BelplanRoutingService, HearingService and others. The arity fixer keyed constructors by that file name, so some constructions received arguments from the wrong class: Error: Unknown named parameter $settingsService Classes are now resolved through the file's own `use` imports, and the pass refuses to act unless it is certain: a constructor that exists but parses to nothing is treated as a PARSE FAILURE and skipped, never as "takes no arguments". It also reads only DEPTH-0 named arguments. A nested construction has its own constructor: new ProcestToolProvider( caseReader: new ProcestCaseReader( settingsService: $settingsService, <-- the INNER call's parameter logger: $logger, Judging those against the outer constructor is what made the first attempt delete valid arguments; that attempt was reverted, and this is its replacement. * fix(tests): restore inherited constructor args, and expect saveObject's real order Two remaining PHPUnit causes in this app. 1. 21 errors: ArgumentCountError on ZgwRulesBase::__construct(). ZgwZrcRulesService has NO constructor of its own — it INHERITS ZgwRulesBase(logger, settingsService, fieldValidator). An earlier sweep read "no __construct in this file" as "takes no arguments" and dropped the two inherited ones. Both mocks were already built two lines above; they had simply stopped being passed. 2. 2 TypeErrors: the doubles declared function (string $r, string $s, array $obj) which is the OLD positional saveObject($register, $schema, $object). ObjectServiceInterface::saveObject() takes $object FIRST, and the caller uses named arguments, so the double receives them in the contract's order. The with() expectation had the same assumption and asserted on the third argument. This is the contract doing its job: a signature nobody could see is now one the doubles have to agree with.
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.
Summary
src/router/)<router-view />and mountsCnIndexSidebargloballyCnIndexPagewith schema-driven columns and built-in CRUD dialogsprocest_register.jsonschema bindingsTest plan
🤖 Generated with Claude Code