lots of improvements
This commit is contained in:
@@ -30,18 +30,17 @@ class InitController extends ControllerAbstract
|
||||
// modules - filter by permissions
|
||||
$configuration['modules'] = [];
|
||||
foreach ($this->moduleManager->list() as $module) {
|
||||
if ($module instanceof ModuleBrowserInterface === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if user has permission to view this module
|
||||
// Allow access if user has: {module_handle}, {module_handle}.*, or * permission
|
||||
$handle = $module->handle();
|
||||
if (!$this->hasModuleViewPermission($handle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$configuration['modules'][$handle] = $module->registerBI();
|
||||
|
||||
$integrations = $module->registerBI();
|
||||
if ($integrations !== null) {
|
||||
$configuration['modules'][$handle] = $integrations;
|
||||
}
|
||||
}
|
||||
|
||||
// tenant
|
||||
|
||||
@@ -252,6 +252,29 @@ class ModuleManager
|
||||
$this->repository->deposit($moduleEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot all enabled modules (must be called after container is ready).
|
||||
*/
|
||||
public function modulesBoot(): void
|
||||
{
|
||||
// Only load modules that are enabled in the database
|
||||
$modules = $this->list();
|
||||
$this->logger->debug('Booting enabled modules', ['count' => count($modules)]);
|
||||
foreach ($modules as $module) {
|
||||
$handle = $module->handle();
|
||||
try {
|
||||
$module->boot();
|
||||
$this->logger->debug('Module booted', ['handle' => $handle]);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error('Module boot failed: ' . $handle, [
|
||||
'exception' => $e,
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan filesystem for module directories and return module instances
|
||||
*
|
||||
@@ -315,29 +338,6 @@ class ModuleManager
|
||||
|
||||
return $modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot all enabled modules (must be called after container is ready).
|
||||
*/
|
||||
public function modulesBoot(): void
|
||||
{
|
||||
// Only load modules that are enabled in the database
|
||||
$modules = $this->list();
|
||||
$this->logger->debug('Booting enabled modules', ['count' => count($modules)]);
|
||||
foreach ($modules as $module) {
|
||||
$handle = $module->handle();
|
||||
try {
|
||||
$module->boot();
|
||||
$this->logger->debug('Module booted', ['handle' => $handle]);
|
||||
} catch (Exception $e) {
|
||||
$this->logger->error('Module boot failed: ' . $handle, [
|
||||
'exception' => $e,
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function moduleInstance(string $handle, ?string $namespace = null): ?ModuleInstanceInterface
|
||||
{
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace KTXC\Module;
|
||||
|
||||
use JsonSerializable;
|
||||
use KTXC\Module\Store\ModuleEntry;
|
||||
use KTXF\Module\ModuleBrowserInterface;
|
||||
use KTXF\Module\ModuleConsoleInterface;
|
||||
use KTXF\Module\ModuleInstanceInterface;
|
||||
|
||||
/**
|
||||
@@ -97,6 +99,11 @@ class ModuleObject implements JsonSerializable
|
||||
return '0.0.0';
|
||||
}
|
||||
|
||||
public function permissions(): array
|
||||
{
|
||||
return $this->instance?->permissions() ?? [];
|
||||
}
|
||||
|
||||
// ===== Computed properties =====
|
||||
|
||||
public function needsUpgrade(): bool
|
||||
@@ -153,14 +160,20 @@ class ModuleObject implements JsonSerializable
|
||||
$this->instance?->upgrade();
|
||||
}
|
||||
|
||||
public function bootUi(): array | null
|
||||
public function registerBI(): array | null
|
||||
{
|
||||
return $this->instance?->bootUi() ?? null;
|
||||
if ($this->instance instanceof ModuleBrowserInterface) {
|
||||
return $this->instance->registerBI();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function permissions(): array
|
||||
public function registerCI(): array | null
|
||||
{
|
||||
return $this->instance?->permissions() ?? [];
|
||||
if ($this->instance instanceof ModuleConsoleInterface) {
|
||||
return $this->instance->registerCI();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
38
core/src/composables/useSnackbar.ts
Normal file
38
core/src/composables/useSnackbar.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Simple snackbar/toast notification composable
|
||||
* Uses Vuetify's snackbar component
|
||||
*/
|
||||
import { ref } from 'vue'
|
||||
|
||||
export interface SnackbarOptions {
|
||||
message: string
|
||||
color?: 'success' | 'error' | 'warning' | 'info' | string
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
const snackbarVisible = ref(false)
|
||||
const snackbarMessage = ref('')
|
||||
const snackbarColor = ref<string>('info')
|
||||
const snackbarTimeout = ref(3000)
|
||||
|
||||
export function useSnackbar() {
|
||||
const showSnackbar = (options: SnackbarOptions) => {
|
||||
snackbarMessage.value = options.message
|
||||
snackbarColor.value = options.color || 'info'
|
||||
snackbarTimeout.value = options.timeout || 3000
|
||||
snackbarVisible.value = true
|
||||
}
|
||||
|
||||
const hideSnackbar = () => {
|
||||
snackbarVisible.value = false
|
||||
}
|
||||
|
||||
return {
|
||||
snackbarVisible,
|
||||
snackbarMessage,
|
||||
snackbarColor,
|
||||
snackbarTimeout,
|
||||
showSnackbar,
|
||||
hideSnackbar,
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,21 @@ export interface ModuleObject {
|
||||
|
||||
export type ModuleCollection = Record<string, ModuleObject>;
|
||||
|
||||
// Module-side integration types (before prefixing by the loader)
|
||||
export interface ModuleIntegrationItem {
|
||||
// Module integration types
|
||||
|
||||
/**
|
||||
* Base interface for module integrations
|
||||
*/
|
||||
export interface ModuleIntegrationBase {
|
||||
id: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* UI Navigation integration item
|
||||
* Represents a single clickable entry in a menu or navigation structure
|
||||
*/
|
||||
export interface ModuleIntegrationItem extends ModuleIntegrationBase {
|
||||
type?: 'item';
|
||||
label: string;
|
||||
caption?: string;
|
||||
@@ -30,8 +42,11 @@ export interface ModuleIntegrationItem {
|
||||
meta?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface ModuleIntegrationGroup {
|
||||
id: string;
|
||||
/**
|
||||
* UI Navigation integration group
|
||||
* Represents a group of related navigation items, potentially with its own label and icon
|
||||
*/
|
||||
export interface ModuleIntegrationGroup extends ModuleIntegrationBase {
|
||||
type: 'group';
|
||||
label?: string;
|
||||
caption?: string;
|
||||
@@ -47,5 +62,6 @@ export type ModuleIntegrationEntry = ModuleIntegrationItem | ModuleIntegrationGr
|
||||
export interface ModuleIntegrations {
|
||||
system_menu?: ModuleIntegrationEntry[];
|
||||
user_menu?: ModuleIntegrationEntry[];
|
||||
[key: string]: ModuleIntegrationEntry[] | undefined;
|
||||
|
||||
[key: string]: ModuleIntegrationEntry[] | ModuleIntegrationBase[] | undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user