ability to expose plugin's config on frontend javascript

Massimo Melina committed Feb 26, 2023 at 23:59 UTC ed7d54bea4cad68b6c9232e8cf68c15d8c66e23e
4 files changed +25 -5
dev-plugins.md
+1
@@ -76,6 +76,7 @@ Currently, these properties are supported:
76 - `label: string` what name to display next to the field. Default is based on `key`.
77 - `defaultValue: any` value to be used when nothing is set.
78 - `helperText: string` extra text printed next to the field.
79 +- `frontend: boolean` expose this setting on the frontend, so that javascript can access it as HFS.plugins[PLUGIN_NAME][CONFIG_KEY]
80
81 Based on `type`, other properties are supported:
82 - `string`
src/const.ts
+1 -1
@@ -17,7 +17,7 @@ export const VERSION = pkg.version
17 export const DAY = 86_400_000
18 export const SESSION_DURATION = DAY
19
20 -export const API_VERSION = 5 // afterEntryName
20 +export const API_VERSION = 6 // config.frontend
21 export const COMPATIBLE_API_VERSION = 1 // while changes in the api are not breaking, this number stays the same, otherwise is made equal to API_VERSION
22
23 export const SPECIAL_URI = '/~/'
src/misc.ts
+12 -2
@@ -32,8 +32,18 @@ export function setHidden<T, ADD>(dest: T, src: ADD) {
32 }))) as T & ADD
33 }
34
35 -export function objSameKeys<S extends object,VR=any>(src: S, newValue:(value:Truthy<S[keyof S]>, key:keyof S)=>any) {
36 - return Object.fromEntries(Object.entries(src).map(([k,v]) => [k, newValue(v,k as keyof S)])) as { [K in keyof S]:VR }
35 +export function objSameKeys<S extends object,VR=any>(
36 + src: S,
37 + newValue: (value:Truthy<S[keyof S]>, key:keyof S, skip:()=>void)=>any
38 +) {
39 + let skipped = false
40 + const pairs = Object.entries(src).map( ([k,v]) => {
41 + skipped = false
42 + const newV = newValue(v, k as keyof S, skip)
43 + return !skipped && [k, newV]
44 + })
45 + return Object.fromEntries(pairs.filter(Boolean)) as { [K in keyof S]:VR }
46 + function skip() { skipped = true }
47 }
48
49 export function wait(ms: number) {
src/serveGuiFiles.ts
+11 -2
@@ -12,12 +12,13 @@ import {
12 VERSION
13 } from './const'
14 import { serveFile } from './serveFile'
15 -import { mapPlugins } from './plugins'
15 +import { getPluginConfigFields, mapPlugins, pluginsConfig } from './plugins'
16 import { refresh_session } from './api.auth'
17 import { ApiError } from './apiMiddleware'
18 import { join, extname } from 'path'
19 -import { getOrSet } from './misc'
19 +import { getOrSet, objSameKeys, onlyTruthy } from './misc'
20 import { favicon, title } from './adminApis'
21 +import _ from 'lodash'
22
23 // in case of dev env we have our static files within the 'dist' folder'
24 const DEV_STATIC = process.env.DEV ? 'dist/' : ''
@@ -84,6 +85,14 @@ async function treatIndex(ctx: Koa.Context, body: string, filesUri: string) {
85 VERSION,
86 API_VERSION,
87 session: session instanceof ApiError ? null : session,
88 + // expose plugins' configs that were declared with 'frontend' attribute
89 + plugins: Object.fromEntries(onlyTruthy(mapPlugins((pl,name) => {
90 + const configs = objSameKeys(getPluginConfigFields(name), (v,k,skip) =>
91 + !v.frontend ? skip() :
92 + (pluginsConfig.get()?.[name]?.[k] ?? pl.getData().config?.[k]?.defaultValue)
93 + )
94 + return !_.isEmpty(configs) && [name, configs]
95 + })))
96 }, null, 4)}
97 document.documentElement.setAttribute('ver', '${VERSION.split('-')[0] /*for style selectors*/}')
98 </script>