Files
InvoiceShelf/Modules/HelloWorld/resources/dist/init.js
Darko Gjorgjijoski b73dcb5278 fix: boot app + AI driver registration on invoiceshelf/modules 3.0.3 (via VCS) (#655)
* fix(deps): require invoiceshelf/modules ^3.0.2 (adds registerExchangeRateDriver)

DriverRegistryProvider::registerExchangeRateDrivers() calls
Registry::registerExchangeRateDriver(), which only exists in
invoiceshelf/modules >= 3.0.2. The constraint (^3.0) and the committed
lock (3.0.1) allowed/pinned versions without it, so a fresh
`composer install` (CI, Docker, new clones) boots into:

  Call to undefined method InvoiceShelf\Modules\Registry::registerExchangeRateDriver()

Pin to ^3.0.2 and update the lock so every install gets a version that
has the method. `php artisan package:discover` verified clean.

* fix(ai): register the AI driver via the generic Registry::registerDriver('ai', ...)

registerAiDriver() is a convenience wrapper that is NOT present in any
published invoiceshelf/modules release (only the generic registerDriver()
and registerExchangeRateDriver() ship), so DriverRegistryProvider crashed
app boot on a clean composer install:

  Call to undefined method InvoiceShelf\Modules\Registry::registerAiDriver()

Use registerDriver('ai', 'openrouter', ...) instead -- it stores under the
'ai' type exactly like the wrapper would, and AiConfigurationService /
AiDriverFactory read it back via allDrivers('ai') / driverMeta('ai', ...).

Verified by clean-reinstalling invoiceshelf/modules (no local patch) and
running `php artisan package:discover` -> boots clean.

* style: fix pre-existing Pint violations in backup services

BackupService.php and BackupConfigurationFactory.php (untouched by this
PR's boot fix) carried style violations from an earlier domain-reorg
refactor (6d1816bd). `pint --test` checks the whole tree and runs on any
PR that touches PHP, so these failed CI here. Auto-fixed with Pint
(braces_position, no_unused_imports, single_line_empty_body) so the check
goes green.

* build(deps): pull invoiceshelf/modules ^3.0.3 via VCS, restore registerAiDriver()

The 3.0.3 release adds Registry::registerAiDriver() (the method DriverRegistryProvider
and AiDriverFactoryTest call). Packagist has the package frozen, so resolve it directly
from the canonical GitHub repo via a composer VCS repository and require ^3.0.3 (the tag
exists; the freeze is Packagist-side only).

Now that the method ships, restore DriverRegistryProvider to Registry::registerAiDriver()
— reverting the temporary generic registerDriver('ai', ...) workaround — so it matches the
package's intended API and the existing tests. The provider is now net-identical to 3.x.

Verified: php artisan package:discover boots clean; the AI suite (incl. the previously
failing AiDriverFactoryTest) passes.

* test: provision modules_statuses.json in the test bootstrap

The Modules/HelloWorld integration test needs the module enabled at the nwidart
level, read from storage/app/modules_statuses.json at app boot. That file is
gitignored (created locally by `module:make`), so it's absent on CI and fresh
clones — HelloWorld stays disabled and the 5 integration tests fail with 404s.

Provision it (only if missing) in tests/Pest.php before any test boots the app,
so CI matches a local dev environment. Full suite: 462 pass.

* fix(test): enable HelloWorld via a committed modules_statuses.json

The Modules/HelloWorld integration test needs the module enabled at the nwidart
level — read from storage/app/modules_statuses.json by FileActivator. That file
is gitignored, so it's absent in CI / fresh clones, leaving HelloWorld disabled
and the 5 integration tests failing with 404s.

The previous tests/Pest.php provisioning (60a7f0d6) only worked under
`./vendor/bin/pest`. CI runs `php artisan test`, which boots the console app
first; FileActivator reads and caches the (absent) statuses at construction
BEFORE Pest.php runs, so test-runtime provisioning is too late. The file must
exist before any boot.

Commit the file via a storage/app/.gitignore negation, and revert the
ineffective Pest.php hack. Prod-safe: Modules/ is gitignored and not copied by
release.yaml, so a phantom "HelloWorld: true" status is ignored by nwidart (no
such module on disk). bootstrap/cache/modules.php is gitignored (absent in CI),
so nothing overrides the committed file.

Verified with `php artisan test --filter=HelloWorld` (the CI command) and the
full suite: 462 pass; pint clean.

* fix(test): commit the Modules/HelloWorld sample module

HelloWorldIntegrationTest exercises Modules/HelloWorld end-to-end, but Modules/
was gitignored (/Modules), so the module was absent from the repo and from CI —
the 5 integration tests 404'd, and the committed modules_statuses.json merely
enabled a module that wasn't there.

Track Modules/HelloWorld (the test fixture) via a `/Modules/*` + `!HelloWorld`
negation. Not shipped to prod (release.yaml omits Modules/). Now the module is
present, autoloaded (merge-plugin), and enabled (statuses file), so its provider
boots and the menu/settings/routes register.

* build: drop the boost:update post-update-cmd hook (breaks CI)

laravel/boost gates its commands to the local environment, so `php artisan
boost:update` fails in CI ("There are no commands defined in the boost
namespace"), making composer's post-update-cmd return exit 1.

It only began failing the build once Modules/HelloWorld/composer.json was
committed: the wikimedia merge-plugin then runs composer's update path on a
plain `composer install`, triggering post-update-cmd. Drop the auto-update
hook (run `boost:update` manually when needed); vendor:publish stays.
2026-06-05 14:57:06 +02:00

84 lines
3.2 KiB
JavaScript
Vendored

const { createBlock: e, createElementVNode: t, createTextVNode: n, createVNode: r, openBlock: i, ref: a, resolveComponent: o, toDisplayString: s, withCtx: c } = window.__invoiceshelf_vue;
//#region resources/js/pages/DashboardPage.vue
var l = { class: "p-6" }, u = { class: "flex items-center gap-3" }, d = { class: "text-xl font-semibold text-heading" }, f = { class: "mt-6 rounded-lg bg-surface-secondary p-4" }, p = { class: "space-y-1.5 text-sm text-muted" }, m = { class: "flex items-start gap-2" }, h = { class: "flex items-start gap-2" }, g = { class: "flex items-start gap-2" }, _ = {
__name: "DashboardPage",
setup(_) {
let v = a("Hello, world!");
return (a, _) => {
let y = o("BaseBreadcrumbItem"), b = o("BaseBreadcrumb"), x = o("BasePageHeader"), S = o("BaseIcon"), C = o("BaseCard"), w = o("BasePage");
return i(), e(w, null, {
default: c(() => [r(x, { title: "Hello World" }, {
default: c(() => [r(b, null, {
default: c(() => [r(y, {
title: "Home",
to: "dashboard"
}), r(y, {
title: "Hello World",
to: "#",
active: ""
})]),
_: 1
})]),
_: 1
}), r(C, { class: "mt-6" }, {
default: c(() => [t("div", l, [
t("div", u, [r(S, {
name: "HandRaisedIcon",
class: "h-8 w-8 text-primary-500"
}), t("h2", d, s(v.value), 1)]),
_[12] ||= t("p", { class: "mt-3 text-sm text-muted leading-relaxed" }, [
n(" This page is provided by the "),
t("strong", null, "HelloWorld"),
n(" module. It demonstrates how modules can ship their own Vue pages that render inside the InvoiceShelf SPA using globally registered Base components. ")
], -1),
t("div", f, [_[11] ||= t("h3", { class: "text-sm font-semibold text-heading mb-2" }, "How it works", -1), t("ul", p, [
t("li", m, [
r(S, {
name: "CheckIcon",
class: "h-4 w-4 text-green-500 shrink-0 mt-0.5"
}),
_[0] ||= n(" Module ships a compiled ", -1),
_[1] ||= t("code", { class: "text-primary-600" }, "init.js", -1),
_[2] ||= n(" that calls ", -1),
_[3] ||= t("code", { class: "text-primary-600" }, "window.InvoiceShelf.booting()", -1)
]),
t("li", h, [
r(S, {
name: "CheckIcon",
class: "h-4 w-4 text-green-500 shrink-0 mt-0.5"
}),
_[4] ||= n(" The callback receives ", -1),
_[5] ||= t("code", { class: "text-primary-600" }, "(app, router)", -1),
_[6] ||= n(" and adds routes via ", -1),
_[7] ||= t("code", { class: "text-primary-600" }, "router.addRoute()", -1)
]),
t("li", g, [
r(S, {
name: "CheckIcon",
class: "h-4 w-4 text-green-500 shrink-0 mt-0.5"
}),
_[8] ||= n(" Vue pages use globally registered ", -1),
_[9] ||= t("code", { class: "text-primary-600" }, "Base*", -1),
_[10] ||= n(" components — no imports needed ", -1)
])
])])
])]),
_: 1
})]),
_: 1
});
};
}
};
//#endregion
//#region resources/js/init.ts
window.InvoiceShelf.booting((e, t) => {
t.addRoute("admin", {
path: "modules/hello-world/dashboard",
name: "modules.hello-world.dashboard",
component: _,
meta: { requiresAuth: !0 }
});
});
//#endregion