import type { RouteLocationRaw, RouteRecordRaw, RouteRecordName } from 'vue-router'; import type { Component } from '@vue/runtime-core'; type Join = T extends [] ? '' : T extends [string | number | boolean | bigint] ? `${T[0]}` : T extends [string | number | boolean | bigint, ...infer U] ? `${T[0]}${D}${Join}` : string; type BVersion = Join<[number, number], '.'> | Join<[number, number, number], '.'> type Version = BVersion | Join<[BVersion, string], '-'> export namespace FG_Plugin { /** * Interface defining a Flaschengeist plugin */ export interface Plugin { /** Unique identifier for this plugin, we recommend using a FQN like com.example.my_plugin */ id: string, /** Arbitrary name of the plugin used inside admin view etc */ name: string; /** Version of this plugin, used for dependencies. MUST be semver parsable */ version: string; /** Widgets provided by this plugin */ widgets: Widget[]; /** Other frontend modules needed for this plugin to work correctly */ requiredModules: [string, Version?][]; /** Backend modules needed for this plugin to work correctly */ requiredBackendModules: [string, Version?][]; /** Menu entries for authenticated users */ innerRoutes?: MenuRoute[]; /** Public menu entries (without authentification) */ outerRoutes?: MenuRoute[]; /** Routes without menu links, for internal usage */ internalRoutes?: NamedRouteRecordRaw[]; /** Handle notifications, defaults to boot/plugins.ts:translateNotification() */ notification?(msg: FG.Notification): FG_Plugin.Notification; } /** * Defines the loaded state of the Flaschengeist */ export interface Flaschengeist { /** All loaded plugins */ plugins: LoadedPlugin[]; /** All routes, combined from all plugins */ routes: RouteRecordRaw[]; /** All menu entries */ menuLinks: MenuLink[]; /** All inner shortcuts */ shortcuts: Shortcut[]; /** All outer shortcuts */ outerShortcuts: Shortcut[]; /** All widgets */ widgets: Widget[]; } /** * Interface for a frontend notification */ export interface Notification extends FG.Notification { /** If set a button for accepting will be shown, this function will get called before deleting the notification */ accept?(): Promise; /** If set this function is called before the notification gets deleted */ reject?(): Promise; /** If set the notification text is interpreted as a link to this location */ link?: RouteLocationRaw; /** If set this icon is used */ icon?: string; } /** * Loaded Flaschengeist plugin */ interface LoadedPlugin { name: string; version: string; notification(msg: FG.Notification): FG_Plugin.Notification; } /** * Defines a shortcut link */ export interface Shortcut { link: RouteRecordName; icon: string; permissions?: string[]; } type NamedRouteRecordRaw = RouteRecordRaw & { name: RouteRecordName; }; /** * Defines a main menu entry along with the route * Used when defining a plugin */ export interface MenuRoute extends MenuEntry { route: NamedRouteRecordRaw; shortcut?: boolean; children?: this[]; } /** * Defines a menu entry in the main menu */ export interface MenuLink extends MenuEntry { /** Name of the target route */ link: RouteRecordName; } /** * Base interface for internal use */ interface MenuEntry { title: string | (() => string); icon: string; permissions?: string[]; children?: this[]; } /** * Widget object for the dashboard */ export interface Widget { name: string; priority: number; permissions: FG.Permission[]; widget: Component; } }