Makes finally dynamic component work??
This commit is contained in:
@@ -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'
|
||||||
|
|||||||
@@ -34,25 +34,25 @@ describe('Config', () => {
|
|||||||
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();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 };
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user