396 lines
13 KiB
Vue
396 lines
13 KiB
Vue
<script setup>
|
|
definePageMeta({
|
|
title: "Plugin Manager",
|
|
middleware: ["auth"],
|
|
requiresAuth: true,
|
|
});
|
|
|
|
// Quick stats for dashboard
|
|
const pluginStats = ref({
|
|
installed: 3,
|
|
active: 3,
|
|
available: 4,
|
|
updates: 2
|
|
});
|
|
|
|
// Quick actions
|
|
const quickActions = ref([
|
|
{
|
|
title: "Browse Store",
|
|
description: "Discover new plugins and applications",
|
|
icon: "mdi:store",
|
|
color: "blue",
|
|
path: "/devtool/plugin-manager/store"
|
|
},
|
|
{
|
|
title: "My Plugins",
|
|
description: "Manage installed plugins",
|
|
icon: "mdi:puzzle",
|
|
color: "green",
|
|
path: "/devtool/plugin-manager/installed"
|
|
},
|
|
{
|
|
title: "Upload Plugin",
|
|
description: "Install custom plugin packages",
|
|
icon: "mdi:cloud-upload",
|
|
color: "purple",
|
|
path: "/devtool/plugin-manager/upload"
|
|
},
|
|
{
|
|
title: "Plugin Settings",
|
|
description: "Configure plugin system settings",
|
|
icon: "mdi:cog",
|
|
color: "gray",
|
|
path: "/devtool/plugin-manager/settings"
|
|
}
|
|
]);
|
|
|
|
// Recently installed plugins
|
|
const recentPlugins = ref([
|
|
{
|
|
id: 1,
|
|
name: "notification-management",
|
|
displayName: "Notification Management System",
|
|
version: "1.2.0",
|
|
description: "Complete notification system with templates, scheduling, and analytics",
|
|
status: "active",
|
|
author: "CORRAD Team",
|
|
installDate: "2024-01-15",
|
|
icon: "mdi:bell-ring",
|
|
color: "orange",
|
|
authentik: {
|
|
applicationSlug: "notification-management",
|
|
requiredScopes: ["notifications:read", "notifications:write", "notifications:admin"],
|
|
groups: ["notification-users", "notification-admins"]
|
|
},
|
|
menuItems: 6,
|
|
apiEndpoints: 2,
|
|
migrations: 3
|
|
},
|
|
{
|
|
id: 2,
|
|
name: "report-management",
|
|
displayName: "Report Management System",
|
|
version: "1.0.0",
|
|
description: "Advanced reporting system integrated with Metabase for analytics and dashboards",
|
|
status: "active",
|
|
author: "CORRAD Team",
|
|
installDate: "2024-01-12",
|
|
icon: "mdi:chart-line",
|
|
color: "blue",
|
|
authentik: {
|
|
applicationSlug: "report-management",
|
|
requiredScopes: ["reports:read", "reports:write", "reports:admin"],
|
|
groups: ["report-users", "report-admins"]
|
|
},
|
|
menuItems: 5,
|
|
apiEndpoints: 3,
|
|
migrations: 2
|
|
},
|
|
{
|
|
id: 3,
|
|
name: "rbac",
|
|
displayName: "RBAC System",
|
|
version: "1.0.0",
|
|
description: "Role-Based Access Control system integrated with Authentik",
|
|
status: "active",
|
|
author: "CORRAD Team",
|
|
installDate: "2024-01-10",
|
|
icon: "mdi:shield-account",
|
|
color: "green",
|
|
authentik: {
|
|
applicationSlug: "rbac-system",
|
|
requiredScopes: ["rbac:read", "rbac:write", "rbac:admin"],
|
|
groups: ["rbac-users", "rbac-admins"]
|
|
},
|
|
menuItems: 4,
|
|
apiEndpoints: 4,
|
|
migrations: 1
|
|
}
|
|
]);
|
|
|
|
// Plugin updates available
|
|
const availableUpdates = ref([
|
|
{
|
|
id: 4,
|
|
name: "audit-trail",
|
|
displayName: "Audit Trail System",
|
|
currentVersion: "1.0.0",
|
|
newVersion: "1.1.0",
|
|
updateSize: "2.1 MB",
|
|
icon: "mdi:file-document-alert",
|
|
color: "purple"
|
|
},
|
|
{
|
|
id: 5,
|
|
name: "queue-management",
|
|
displayName: "Queue Management System",
|
|
currentVersion: "1.0.0",
|
|
newVersion: "1.0.1",
|
|
updateSize: "800 KB",
|
|
icon: "mdi:format-list-numbered",
|
|
color: "indigo"
|
|
}
|
|
]);
|
|
|
|
const getColorClasses = (color, type = 'bg') => {
|
|
const colorMap = {
|
|
bg: {
|
|
blue: 'bg-blue-100 text-blue-600',
|
|
green: 'bg-green-100 text-green-600',
|
|
purple: 'bg-purple-100 text-purple-600',
|
|
orange: 'bg-orange-100 text-orange-600',
|
|
indigo: 'bg-indigo-100 text-indigo-600',
|
|
red: 'bg-red-100 text-red-600',
|
|
gray: 'bg-gray-100 text-gray-600'
|
|
},
|
|
hover: {
|
|
blue: 'hover:bg-blue-200',
|
|
green: 'hover:bg-green-200',
|
|
purple: 'hover:bg-purple-200',
|
|
orange: 'hover:bg-orange-200',
|
|
indigo: 'hover:bg-indigo-200',
|
|
red: 'hover:bg-red-200',
|
|
gray: 'hover:bg-gray-200'
|
|
}
|
|
};
|
|
return colorMap[type][color] || colorMap[type]['gray'];
|
|
};
|
|
|
|
const navigateToAction = (path) => {
|
|
navigateTo(path);
|
|
};
|
|
|
|
const getStatusBadgeVariant = (status) => {
|
|
return status === 'active' ? 'success' : 'secondary';
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<LayoutsBreadcrumb />
|
|
|
|
<!-- Welcome Header -->
|
|
<rs-card class="mb-6">
|
|
<template #body>
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-900 mb-2">Plugin Manager</h1>
|
|
<p class="text-gray-600">
|
|
Manage your application ecosystem. Install, configure, and organize plugins to extend functionality.
|
|
</p>
|
|
</div>
|
|
<div class="hidden md:block">
|
|
<Icon name="mdi:puzzle" size="64" class="text-primary/20" />
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<!-- Stats Overview -->
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
|
|
<rs-card class="text-center">
|
|
<template #body>
|
|
<div class="p-4">
|
|
<div class="flex items-center justify-center mb-2">
|
|
<div class="bg-blue-100 text-blue-600 p-3 rounded-full">
|
|
<Icon name="mdi:puzzle" size="24" />
|
|
</div>
|
|
</div>
|
|
<h3 class="text-2xl font-bold text-gray-900">{{ pluginStats.installed }}</h3>
|
|
<p class="text-sm text-gray-600">Installed</p>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<rs-card class="text-center">
|
|
<template #body>
|
|
<div class="p-4">
|
|
<div class="flex items-center justify-center mb-2">
|
|
<div class="bg-green-100 text-green-600 p-3 rounded-full">
|
|
<Icon name="mdi:check-circle" size="24" />
|
|
</div>
|
|
</div>
|
|
<h3 class="text-2xl font-bold text-gray-900">{{ pluginStats.active }}</h3>
|
|
<p class="text-sm text-gray-600">Active</p>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<rs-card class="text-center">
|
|
<template #body>
|
|
<div class="p-4">
|
|
<div class="flex items-center justify-center mb-2">
|
|
<div class="bg-purple-100 text-purple-600 p-3 rounded-full">
|
|
<Icon name="mdi:store" size="24" />
|
|
</div>
|
|
</div>
|
|
<h3 class="text-2xl font-bold text-gray-900">{{ pluginStats.available }}</h3>
|
|
<p class="text-sm text-gray-600">Available</p>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<rs-card class="text-center">
|
|
<template #body>
|
|
<div class="p-4">
|
|
<div class="flex items-center justify-center mb-2">
|
|
<div class="bg-orange-100 text-orange-600 p-3 rounded-full">
|
|
<Icon name="mdi:update" size="24" />
|
|
</div>
|
|
</div>
|
|
<h3 class="text-2xl font-bold text-gray-900">{{ pluginStats.updates }}</h3>
|
|
<p class="text-sm text-gray-600">Updates</p>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<rs-card class="mb-6">
|
|
<template #header>
|
|
<div class="flex items-center">
|
|
<Icon name="mdi:lightning-bolt" class="mr-2" />
|
|
Quick Actions
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<div
|
|
v-for="action in quickActions"
|
|
:key="action.title"
|
|
class="group p-6 rounded-lg border-2 border-gray-200 hover:border-primary cursor-pointer transition-all duration-200 hover:shadow-md"
|
|
@click="navigateToAction(action.path)"
|
|
>
|
|
<div class="text-center">
|
|
<div
|
|
:class="[getColorClasses(action.color), getColorClasses(action.color, 'hover')]"
|
|
class="w-16 h-16 mx-auto rounded-full flex items-center justify-center mb-4 transition-colors"
|
|
>
|
|
<Icon :name="action.icon" size="32" />
|
|
</div>
|
|
<h3 class="font-semibold text-lg text-gray-900 mb-2 group-hover:text-primary transition-colors">
|
|
{{ action.title }}
|
|
</h3>
|
|
<p class="text-gray-600 text-sm">{{ action.description }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
<!-- Recently Installed -->
|
|
<rs-card>
|
|
<template #header>
|
|
<div class="flex items-center justify-between w-full">
|
|
<div class="flex items-center">
|
|
<Icon name="mdi:history" class="mr-2" />
|
|
Recently Installed
|
|
</div>
|
|
<NuxtLink
|
|
to="/devtool/plugin-manager/installed"
|
|
class="text-primary hover:text-primary/80 text-sm font-medium"
|
|
>
|
|
View All
|
|
</NuxtLink>
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<div class="space-y-4">
|
|
<div
|
|
v-for="plugin in recentPlugins"
|
|
:key="plugin.id"
|
|
class="flex items-center p-4 rounded-lg border border-gray-200 hover:shadow-sm transition-shadow"
|
|
>
|
|
<div
|
|
:class="getColorClasses(plugin.color)"
|
|
class="w-12 h-12 rounded-lg flex items-center justify-center mr-4"
|
|
>
|
|
<Icon :name="plugin.icon" size="24" />
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="flex items-center justify-between">
|
|
<h4 class="font-medium text-gray-900 truncate">{{ plugin.displayName }}</h4>
|
|
<rs-badge :variant="getStatusBadgeVariant(plugin.status)" size="sm">
|
|
{{ plugin.status }}
|
|
</rs-badge>
|
|
</div>
|
|
<p class="text-sm text-gray-600 mt-1">v{{ plugin.version }} • {{ plugin.author }}</p>
|
|
<div class="flex items-center space-x-3 mt-2 text-xs text-gray-500">
|
|
<span class="flex items-center">
|
|
<Icon name="mdi:menu" size="12" class="mr-1" />
|
|
{{ plugin.menuItems }} menus
|
|
</span>
|
|
<span class="flex items-center">
|
|
<Icon name="mdi:api" size="12" class="mr-1" />
|
|
{{ plugin.apiEndpoints }} APIs
|
|
</span>
|
|
<span class="flex items-center">
|
|
<Icon name="mdi:database" size="12" class="mr-1" />
|
|
{{ plugin.migrations }} migrations
|
|
</span>
|
|
</div>
|
|
<p class="text-xs text-gray-500 mt-1">Installed {{ plugin.installDate }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div v-if="recentPlugins.length === 0" class="text-center py-8">
|
|
<Icon name="mdi:puzzle-outline" size="48" class="mx-auto text-gray-400 mb-2" />
|
|
<p class="text-gray-500">No plugins installed yet</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
|
|
<!-- Available Updates -->
|
|
<rs-card>
|
|
<template #header>
|
|
<div class="flex items-center justify-between w-full">
|
|
<div class="flex items-center">
|
|
<Icon name="mdi:update" class="mr-2" />
|
|
Available Updates
|
|
<rs-badge v-if="availableUpdates.length > 0" variant="warning" size="sm" class="ml-2">
|
|
{{ availableUpdates.length }}
|
|
</rs-badge>
|
|
</div>
|
|
<rs-button size="sm" variant="outline" v-if="availableUpdates.length > 0">
|
|
Update All
|
|
</rs-button>
|
|
</div>
|
|
</template>
|
|
<template #body>
|
|
<div class="space-y-4">
|
|
<div
|
|
v-for="update in availableUpdates"
|
|
:key="update.id"
|
|
class="flex items-center p-4 rounded-lg border border-gray-200 hover:shadow-sm transition-shadow"
|
|
>
|
|
<div
|
|
:class="getColorClasses(update.color)"
|
|
class="w-12 h-12 rounded-lg flex items-center justify-center mr-4"
|
|
>
|
|
<Icon :name="update.icon" size="24" />
|
|
</div>
|
|
<div class="flex-1 min-w-0">
|
|
<h4 class="font-medium text-gray-900">{{ update.displayName }}</h4>
|
|
<p class="text-sm text-gray-600 mt-1">
|
|
{{ update.currentVersion }} → {{ update.newVersion }}
|
|
</p>
|
|
<p class="text-xs text-gray-500 mt-1">{{ update.updateSize }}</p>
|
|
</div>
|
|
<rs-button size="sm" variant="primary">
|
|
Update
|
|
</rs-button>
|
|
</div>
|
|
|
|
<div v-if="availableUpdates.length === 0" class="text-center py-8">
|
|
<Icon name="mdi:check-circle" size="48" class="mx-auto text-green-400 mb-2" />
|
|
<p class="text-gray-500">All plugins are up to date</p>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</rs-card>
|
|
</div>
|
|
</div>
|
|
</template> |