- GET /plugins (backend.view_plugins, superusers always pass) lists the plugins from party.Installed, or party.Activated IDs for older builds, with the built framework version and whether the registry is configured - Settings -> System -> Plugins entry with the new SettingsEntry.path, added only for principals allowed to open it - PluginsView at /system/plugins with an Installed tab (reka-ui Tabs); settings panel, rail, breadcrumbs and page title know the route - OpenAPI and SPA types regenerated; contract, token-class and conformance inventories list the route; en/pl strings; docs
114 lines
3.7 KiB
TypeScript
114 lines
3.7 KiB
TypeScript
// Settings pages the admin may manage (D-21), server-filtered like the
|
|
// navigation. The rail shows "Ustawienia" only when this list is non-empty.
|
|
// An entry is either a singleton settings form (/settings/<code>), a link
|
|
// that opens an admin controller (its `controller` is set) or one of the
|
|
// admin's own screens (its `path` is set, for example /system/plugins).
|
|
import { computed, readonly, ref } from 'vue'
|
|
import { api } from '../api/client'
|
|
import { controllerPath } from '../app/controllerRoutes'
|
|
import type { SettingsEntry } from '../api/types'
|
|
|
|
const entries = ref<SettingsEntry[]>([])
|
|
|
|
export const settings = readonly(entries)
|
|
|
|
export const hasSettings = computed(() => entries.value.length > 0)
|
|
|
|
export async function loadSettings(): Promise<SettingsEntry[]> {
|
|
const { data, response } = await api.GET('/settings')
|
|
entries.value = response.ok && data ? data.data : []
|
|
return entries.value
|
|
}
|
|
|
|
export function setSettings(next: SettingsEntry[]): void {
|
|
entries.value = next
|
|
}
|
|
|
|
export function settingsEntry(code: string): SettingsEntry | null {
|
|
return entries.value.find((entry) => entry.code === code) ?? null
|
|
}
|
|
|
|
/**
|
|
* Route a settings entry opens: its own SPA path for an admin screen, its
|
|
* controller for a link entry (the index when the ID is malformed),
|
|
* otherwise its singleton form.
|
|
*/
|
|
export function settingsPath(entry: SettingsEntry): string {
|
|
if (entry.path) {
|
|
return entry.path
|
|
}
|
|
if (entry.controller) {
|
|
return controllerPath(entry.controller) ?? '/settings'
|
|
}
|
|
return `/settings/${encodeURIComponent(entry.code)}`
|
|
}
|
|
|
|
/** The link entry that opens the given controller, if any. */
|
|
export function settingsLinkFor(controllerId: string | null): SettingsEntry | null {
|
|
if (!controllerId) {
|
|
return null
|
|
}
|
|
return entries.value.find((entry) => entry.controller !== '' && entry.controller === controllerId) ?? null
|
|
}
|
|
|
|
/** The entry that opens the admin screen at path (entry.path), if any. */
|
|
export function settingsEntryForPath(path: string): SettingsEntry | null {
|
|
return entries.value.find((entry) => !!entry.path && entry.path === path) ?? null
|
|
}
|
|
|
|
/** Entries grouped by category, categories in first-seen order, by order. */
|
|
export const settingsGroups = computed(() => {
|
|
const sorted = entries.value
|
|
.map((entry, index) => ({ entry, index }))
|
|
.sort((a, b) => a.entry.order - b.entry.order || a.index - b.index)
|
|
.map(({ entry }) => entry)
|
|
const groups: Array<{ category: string; entries: SettingsEntry[] }> = []
|
|
for (const entry of sorted) {
|
|
let group = groups.find((item) => item.category === entry.category)
|
|
if (!group) {
|
|
group = { category: entry.category, entries: [] }
|
|
groups.push(group)
|
|
}
|
|
group.entries.push(entry)
|
|
}
|
|
return groups
|
|
})
|
|
|
|
/** The settings pages of one category, with the page on screen. */
|
|
export interface SettingsSection {
|
|
category: string
|
|
current: SettingsEntry
|
|
entries: SettingsEntry[]
|
|
}
|
|
|
|
/**
|
|
* The category group of the given entry for the shell's settings panel, in
|
|
* settingsGroups order and without entries of any other category. Null when
|
|
* there is no current entry or its category holds a single page: there is
|
|
* nothing to switch to.
|
|
*/
|
|
export function settingsSectionOf(current: SettingsEntry | null): SettingsSection | null {
|
|
if (!current) {
|
|
return null
|
|
}
|
|
const group = settingsGroups.value.find((item) => item.category === current.category)
|
|
if (!group || group.entries.length < 2) {
|
|
return null
|
|
}
|
|
return { category: group.category, current, entries: group.entries }
|
|
}
|
|
|
|
export function useSettings() {
|
|
return {
|
|
settings,
|
|
hasSettings,
|
|
settingsGroups,
|
|
loadSettings,
|
|
settingsEntry,
|
|
settingsPath,
|
|
settingsLinkFor,
|
|
settingsEntryForPath,
|
|
settingsSectionOf,
|
|
}
|
|
}
|