Makes finally dynamic component work??

This commit is contained in:
2023-08-11 17:04:39 +02:00
parent 09304b9a95
commit 9903497867
6 changed files with 69 additions and 52 deletions

View File

@@ -2,11 +2,13 @@ title: 'Hello World !!'
subtitle: 'actually, I am a new pilot.' subtitle: 'actually, I am a new pilot.'
services: services:
- title: '/Cloud' cloud:
title: '/Cloud'
subtitle: 'Private Cloud Utilities' subtitle: 'Private Cloud Utilities'
icon: 'fas fa-cloud' icon: 'fas fa-cloud'
items: items:
- title: 'NAS' nas:
title: 'NAS'
subtitle: 'Network Attached Storage' subtitle: 'Network Attached Storage'
icon: 'fas fa-hard-drive' icon: 'fas fa-hard-drive'
target: '_blank' target: '_blank'

View File

@@ -33,26 +33,26 @@ describe('Config', () => {
it('should be able to strip custom keys', () => { it('should be able to strip custom keys', () => {
const custom: Config = { const custom: Config = {
title: 'custom', title: 'custom',
secret: {secret: 'some secret'}, secret: { secret: 'some secret' },
services: [ services: {
{ top: {
title: 'top services', title: 'top services',
secret: 'secret', secret: 'secret',
items: [ items: {
{ top: {
title: 'top service', title: 'top service',
url: 'somewhere', url: 'somewhere',
secret: 'secret' secret: 'secret'
} }
] }
} }
] }
}; };
const stripped: Config = stripPrivateFields(custom); const stripped: Config = stripPrivateFields(custom);
expect(stripped.secret).toBeUndefined(); expect(stripped.secret).toBeUndefined();
expect(stripped.services[0].secret).toBeUndefined(); expect(stripped.services.top.secret).toBeUndefined();
expect(stripped.services[0].items[0].secret).toBeUndefined(); expect(stripped.services.top.items.top.secret).toBeUndefined();
}); });
}); });

View File

@@ -21,13 +21,13 @@ export interface ServiceConfig extends SectionConfig {
} }
export interface ServiceGroupConfig extends SectionConfig { export interface ServiceGroupConfig extends SectionConfig {
items: ServiceConfig[]; items: Record<string, ServiceConfig>;
[x: string]: unknown; [x: string]: unknown;
} }
export interface Config extends SectionConfig { export interface Config extends SectionConfig {
services: ServiceGroupConfig[]; services: Record<string, ServiceGroupConfig>;
[x: string]: unknown; [x: string]: unknown;
} }
@@ -41,17 +41,17 @@ type DeepRequired<T> = T extends object
const requiredConfig: DeepRequired<Config> = { const requiredConfig: DeepRequired<Config> = {
title: '', title: '',
subtitle: '', subtitle: '',
services: [ services: {
{ default: {
title: '', title: '',
items: [ items: {
{ default: {
title: '', title: '',
url: '' url: ''
} }
] }
} }
] }
}; };
export function mergeConfig(a: Config, b: any): Config { export function mergeConfig(a: Config, b: any): Config {
@@ -61,7 +61,7 @@ export function mergeConfig(a: Config, b: any): Config {
export const defaultConfig: Config = { export const defaultConfig: Config = {
title: 'Flanders', title: 'Flanders',
services: [] services: {}
}; };
type SPOJO = Record<string, unknown>; type SPOJO = Record<string, unknown>;
@@ -70,29 +70,21 @@ function strip<Type extends SPOJO>(toStrip: Type, reference: Type): Type {
const res: Type = { ...toStrip }; const res: Type = { ...toStrip };
const referenceNames = Object.entries(reference).map(([key, value]) => key); const referenceNames = Object.entries(reference).map(([key, value]) => key);
const allowAny: boolean = referenceNames.length == 1 && referenceNames[0] == 'default';
for (const [key, value] of Object.entries(res)) { for (const [key, value] of Object.entries(res)) {
if (referenceNames.includes(key) == false) { if (referenceNames.includes(key) == false && allowAny == false) {
// remove the object // remove the object
delete res[key]; delete res[key];
continue; continue;
} }
// strips further arrays
if (value instanceof Array) {
const stripped: SPOJO = {};
const childRef = (reference[key] as Array<SPOJO>)[0];
stripped[key] = value.map((v: SPOJO) => strip(v, childRef));
Object.assign(res, stripped);
continue;
}
if (typeof value != 'object') { if (typeof value != 'object') {
continue; continue;
} }
// it is a child object, we strip it further // it is a child object, we strip it further
const stripped: SPOJO = {}; const stripped: SPOJO = {};
stripped[key] = strip(value as SPOJO, reference[key] as SPOJO); const childReference: SPOJO = reference[allowAny ? 'default' : key] as SPOJO;
stripped[key] = strip(value as SPOJO, childReference);
Object.assign(res, stripped); Object.assign(res, stripped);
} }
return res; return res;

View File

@@ -10,18 +10,21 @@ export type ServiceHandler = (input: Partial<ServiceHandlerArgs>) => {
componentPath: string; componentPath: string;
}; };
const services: Record<string, ServiceHandler> = {}; const services: Record<string, [ServiceHandler, string]> = {};
export function registerService(type: string, handler: ServiceHandler) { export function registerService(type: string, handler: ServiceHandler) {
services[type] = handler; services[type] = [handler, type];
} }
export function getService(type: string): ServiceHandler { export function getService(type: string): [ServiceHandler, string] {
const handler = services[type]; const handler = services[type];
if (handler == undefined) { if (handler == undefined) {
return () => { return [
return { data: {}, componentPath: 'generic/GenericServiceCard.svelte' }; () => {
}; return { data: {}, componentPath: 'generic/GenericServiceCard.svelte' };
},
'generic'
];
} }
return handler; return handler;
} }

View File

@@ -1,5 +1,5 @@
import { dev } from '$app/environment'; import { dev } from '$app/environment';
import { config, stripPrivateFields, type Config } from '$lib/config'; import { config, stripPrivateFields, type Config, type ServiceConfig } from '$lib/config';
import type { PageServerLoad } from './$types'; import type { PageServerLoad } from './$types';
import * as yml from 'js-yaml'; import * as yml from 'js-yaml';
import { readFile } from 'fs/promises'; import { readFile } from 'fs/promises';
@@ -17,23 +17,27 @@ async function reloadConfig(): Promise<Config> {
} }
} }
function zip<T>(a: Array<T>, b: Array<T>): Array<Array<T>> {
const size = Math.min(a.length, b.length);
return a.slice(0, size).map((v, i) => [v, b[i]]);
}
export const load: PageServerLoad = async ({ fetch, depends }) => { export const load: PageServerLoad = async ({ fetch, depends }) => {
depends('app:state'); depends('app:state');
const serverConfig = await reloadConfig(); const serverConfig = await reloadConfig();
const clientConfig = stripPrivateFields(serverConfig); const clientConfig = stripPrivateFields(serverConfig);
const groups: Array<string> = Object.entries(serverConfig.services).map(([k, v]) => k);
for (const group of groups) {
const serverGroup = serverConfig.services[group];
const clientGroup = clientConfig.services[group];
for (const [serverGroup, clientGroup] of zip(serverConfig.services, clientConfig.services)) { const services = Object.entries(serverGroup.items).map(([k, v]) => k);
for (const [serverService, clientService] of zip(serverGroup.items, clientGroup.items)) {
const handler = getService(serverService.type || ''); for (const service of services) {
const serverService = serverGroup.items[service] as ServiceConfig;
const clientService = clientGroup.items[service] as ServiceConfig;
const [handler, type] = getService(serverService.type || '');
clientService.type = type;
Object.assign(clientService, handler({ fetch, config: serverService })); Object.assign(clientService, handler({ fetch, config: serverService }));
} }
} }
clientConfig.timestamp = new Date(); clientConfig.timestamp = new Date();
return { config: clientConfig }; return { config: clientConfig, cool: true };
}; };

View File

@@ -1,15 +1,31 @@
import type { PageLoad } from './$types'; import type { PageLoad } from './$types';
export const load: PageLoad = async ({ data }) => { export const load: PageLoad = async ({ data }) => {
for (const group of data.config.services) { const config = { ...data.config };
for (const service of group.items) { const groups: Array<string> = Object.entries(config.services).map(([k, v]) => k);
const components: Record<string, any> = {};
for (const group of groups) {
const services: Array<string> = Object.entries(config.services[group].items).map(
([k, v]) => k
);
for (const s of services) {
const service = data.config.services[group].items[s];
if (components[service.type || 'generic'] != undefined) {
continue;
}
const path = const path =
'../lib/services/' + (service.componentPath || 'generic/GenericServiceCard.svelte'); '../lib/services/' + (service.componentPath || 'generic/GenericServiceCard.svelte');
const module = await import(/* @vite-ignore */ path); const module = await import(/* @vite-ignore */ path);
service.component = module.default; components[service.type || 'generic'] = module.default;
delete service.componentPath; delete service.componentPath;
} }
} }
return { config: data.config };
return { config, components };
}; };