Further Cleanup removing old Compositor

This commit is contained in:
Samuel Andert 2023-08-07 18:34:23 +02:00
parent 2ca67e0981
commit beeb298c35
29 changed files with 208 additions and 479 deletions

View File

@ -1,9 +0,0 @@
<script>
import { AppBar } from '@skeletonlabs/skeleton';
export let store;
</script>
<AppBar>
<!-- <h1 class="h4">{$store.dapp.name}</h1> -->
<!-- <svelte:fragment slot="trail">(actions)</svelte:fragment> -->
</AppBar>

View File

@ -4,9 +4,9 @@
const routes = [
{ path: '/', name: 'Home', icon: 'iconoir:home-simple-door' },
{ path: '/messages', name: 'Messages', icon: 'iconoir:message-text' },
{ path: '/terminal', name: 'Terminal', icon: 'iconoir:message-text' },
{ path: '/wallet', name: 'Wallet', icon: 'iconoir:wallet' },
{ path: '/helloearth', name: 'Hello Earth', icon: 'iconoir:planet-sat' }
{ path: '/composer', name: 'Composer', icon: 'iconoir:planet-sat' }
];
function closeDrawer() {
drawerStore.close();

View File

@ -1,10 +1,8 @@
<script>
import { onMount, afterUpdate } from 'svelte';
import Composite from '$lib/core/Composite.svelte';
import Composer from '$lib/core/refactor/Composer.svelte';
export let store;
let isStoreLoaded = false;
export let me;
let messagesContainer;
@ -21,30 +19,27 @@
afterUpdate(() => {
scrollToBottom();
});
$: if ($store) isStoreLoaded = true;
</script>
{#if isStoreLoaded}
{#if $store.messages}
<main bind:this={messagesContainer} class="w-full h-full p-4 overflow-y-auto">
<div class="grid gap-2">
{#each $store.messages as message}
<div class="p-4 space-y-2 rounded-tl-none card variant-soft">
<header class="flex items-center justify-between">
<p class="font-bold">{message.type} | {message.sender}</p>
<small class="opacity-50">{message.timestamp}</small>
</header>
<p>{message.text}</p>
{#if $me.store.messages}
<main bind:this={messagesContainer} class="w-full h-full p-4 overflow-y-auto">
<div class="grid gap-2">
{#each $me.store.messages as message}
<div class="p-4 space-y-2 rounded-tl-none card variant-soft">
<header class="flex items-center justify-between">
<p class="font-bold">{message.type} | {message.sender}</p>
<small class="opacity-50">{message.timestamp}</small>
</header>
<p>{message.text}</p>
</div>
{#if message.composite}
<div class="overflow-y-auto max-h-80vh">
<Composer composer={message.composite} />
</div>
{#if message.composite}
<div class="overflow-y-auto max-h-80vh">
<Composite composite={message.composite} />
</div>
{/if}
{/each}
</div>
</main>
{/if}
{/if}
{/each}
</div>
</main>
{:else}
<div>Loading...</div>
{/if}

View File

@ -27,7 +27,6 @@
}
}
// Sending message logic
function sendMessage(text) {
if (text && text.trim() !== '') {
const message = {

View File

@ -1,4 +1,4 @@
<script>
<script lang="ts">
import { createMachine, assign } from 'xstate';
import { useMachine } from '@xstate/svelte';
import { superForm } from 'sveltekit-superforms/client';
@ -6,7 +6,7 @@
import { writable, get } from 'svelte/store';
import { createUser } from './userService';
import { derived } from 'svelte/store';
import Composite from '$lib/core/Composite.svelte';
import Composer from '$lib/core/refactor/Composer.svelte';
const initialFormData = { name: '', age: '' };
@ -90,7 +90,7 @@
meta: {
title: 'LitStatus',
buttonLabel: 'next',
composite: {
composer: {
id: 'litStatus',
component: 'LitStatus'
}
@ -189,7 +189,7 @@
</p>
{#if stateMachine.states[$state.value].meta.composite}
<Composite composite={stateMachine.states[$state.value].meta.composite} />
<Composer composer={stateMachine.states[$state.value].meta.composer} />
{/if}
{#if $state.value === 'start'}Welcome{:else if $state.value === 'name'}

View File

@ -0,0 +1,24 @@
<script>
import Icon from '@iconify/svelte';
import { drawerStore } from '@skeletonlabs/skeleton';
const routes = [
{ path: '/composer/stateToState', name: 'StateToState', icon: 'iconoir:align-top-box' },
{ path: '/composer/recipies', name: 'Recipies', icon: 'iconoir:stackoverflow' },
{ path: '/composer/graphql', name: 'GraphQL', icon: 'iconoir:network-right' },
{ path: '/composer/queries', name: 'Queries', icon: 'iconoir:brain-research' },
{ path: '/composer/form', name: 'Form', icon: 'iconoir:input-field' }
];
function closeDrawer() {
drawerStore.close();
}
</script>
<div class="grid grid-cols-3 gap-4 p-12">
{#each routes as route}
<a class="flex flex-col items-center w-64 logo-item" href={route.path} on:click={closeDrawer}>
<Icon icon={route.icon} width="96" height="96" />
<span class="mt-2 text-center">{route.name}</span>
</a>
{/each}
</div>

View File

@ -1,16 +1,5 @@
<script>
import { createMessage } from '$lib/services/messages/messages';
export let me;
function sendMessage() {
const randomNumber = Math.floor(Math.random() * 100) + 1;
const messageData = {
text: `test ${randomNumber}`,
sender: 'ComposerCharly',
type: 'text'
};
createMessage(messageData);
}
</script>
<div class="flex flex-col h-screen border-2 border-green-500">
@ -18,19 +7,16 @@
<p>My ID is: {$me.id}</p>
My state is: {$me.state}
Todo Query:<br />
{#if $me.store.todos}
{#each $me.store.todos as todo}
<p>{todo.text}</p>
{/each}
{/if}
</section>
<button
class="self-center px-4 py-2 font-bold text-white rounded hover:bg-blue-700"
on:click={sendMessage}
>
Send
</button>
<section class="flex-grow p-8 overflow-y-auto">
Messages Query:<br />
{#if $me.store.messages}
{#each $me.store.messages as message}
<p>{message.text}</p>

View File

@ -1,250 +0,0 @@
<script lang="ts">
import { onDestroy } from 'svelte';
import Composite from './Composite.svelte';
import FallBack from './FallBack.svelte';
import components from '$lib/core/componentLoader';
import services from '$lib/core/servicesLoader';
import { dataStore } from '$lib/core/dataLoader';
import { createCompositeStore, getCompositeStore } from '$lib/core/compositeStores';
import { coreServices } from './coreServices';
import { Machine, interpret } from 'xstate';
interface ICompositeLayout {
areas: string;
columns?: string;
rows?: string;
gap?: string;
tailwindClasses?: string;
}
interface IComposite {
layout?: ICompositeLayout;
id: string;
slot?: string;
component?: string;
services?: string[];
map?: Record<string, string>;
store?: Record<string, any>;
children?: IComposite[];
servicesLoaded?: boolean;
machine?: any;
machineService?: any;
}
export let composite: IComposite;
let loadedServices: Record<string, any> = {
core: coreServices
};
let layoutStyle = '';
let machineService;
$: {
layoutStyle = computeLayoutStyle(composite?.layout);
initializeAndLoadServices(composite);
initializeCompositeState(composite);
mapAndSubscribe(composite);
if (composite?.children) {
composite.children.forEach((child) => {
initializeCompositeState(child);
initializeAndLoadServices(child);
mapAndSubscribe(child);
});
}
if (composite?.machine) {
const machine = Machine({ ...composite.machine, id: composite.id });
machineService = interpret(machine).onTransition((state) => {
getCompositeStore(composite.id).update((storeValue) => ({
...storeValue,
machine: { state: state.value }
}));
});
machineService.start();
composite.machineService = machineService;
}
if (composite?.children) {
composite.children.forEach((child) => {
if (child.machine) {
const childMachine = Machine({ ...child.machine, id: child.id });
machineService = interpret(childMachine).onTransition((state) => {
getCompositeStore(child.id).update((storeValue) => ({
...storeValue,
machine: { state: state.value }
}));
});
machineService.start();
child.machineService = machineService;
}
});
}
}
function computeLayoutStyle(layout?: ICompositeLayout): string {
if (!layout) return '';
return `
grid-template-areas: ${layout.areas};
${layout.gap ? `gap: ${layout.gap};` : ''}
${layout.columns ? `grid-template-columns: ${layout.columns};` : ''}
${layout.rows ? `grid-template-rows: ${layout.rows};` : ''}
`;
}
function initializeAndLoadServices(component: IComposite) {
if (!component) return;
if (component.services) {
let servicePromises = component.services.map((serviceName) =>
loadedServices[serviceName]
? Promise.resolve(loadedServices[serviceName])
: loadService(serviceName)
);
Promise.all(servicePromises).then((loaded) => {
loaded.forEach((service, index) => {
loadedServices[component.services[index]] = service;
});
component.servicesLoaded = true;
});
} else {
component.servicesLoaded = true;
}
}
function initializeCompositeState(child: IComposite) {
if (child.id) {
child.store = createCompositeStore(child.id, child.store || {});
}
if (child.children) {
child.children.forEach(initializeCompositeState);
}
}
let unsubscribers = [];
function mapAndSubscribe(component: IComposite) {
if (component.map) {
const localStore = getCompositeStore(component.id);
for (const [localKey, mapping] of Object.entries(component.map)) {
const isDataMapping = mapping.startsWith('@data:');
const isStoreMapping = mapping.startsWith('@');
if (isDataMapping) {
const externalKey = mapping.replace('@data:', '').trim();
const unsubscribe = dataStore.subscribe((store) => {
if (externalKey in store) {
if (store[externalKey] && typeof store[externalKey].subscribe === 'function') {
let innerUnsub = store[externalKey].subscribe((value) => {
localStore.update((storeValue) => ({ ...storeValue, [localKey]: value }));
});
unsubscribers.push(innerUnsub);
} else {
localStore.update((storeValue) => ({
...storeValue,
[localKey]: store[externalKey]
}));
}
}
});
unsubscribers.push(unsubscribe);
} else if (isStoreMapping) {
const [externalID, externalKey] = mapping
.replace('@', '')
.split(':')
.map((item) => item.trim());
const externalStore = getCompositeStore(externalID);
if (externalStore) {
const unsubscribe = externalStore.subscribe((externalState) => {
if (externalState && externalKey in externalState) {
localStore.update((storeValue) => ({
...storeValue,
[localKey]: externalState[externalKey]
}));
}
});
unsubscribers.push(unsubscribe);
}
}
}
}
if (component.children) {
component.children.forEach(mapAndSubscribe);
}
}
onDestroy(() => {
unsubscribers.forEach((unsub) => unsub());
});
async function getComponent(componentName: string) {
if (components[componentName]) {
const module = await components[componentName]();
return module.default;
}
return FallBack;
}
async function loadService(serviceName: string) {
if (services[serviceName]) {
const module = await services[serviceName]();
return module.default || module;
}
return null;
}
async function loadComponentAndService(component: IComposite) {
const componentName = component.component || 'FallBack';
return await getComponent(componentName);
}
</script>
<div
class={`grid w-full h-full overflow-hidden ${composite?.layout?.tailwindClasses || ''}`}
style={layoutStyle}
>
{#if composite?.servicesLoaded}
{#await loadComponentAndService(composite) then Component}
<svelte:component
this={Component}
id={composite.id}
store={getCompositeStore(composite.id)}
machine={composite.machine}
services={loadedServices}
machineService={child.machineService}
/>
{/await}
{/if}
{#if composite?.children}
{#each composite.children as child (child.id)}
<div
class="grid w-full h-full overflow-hidden ${composite?.layout?.tailwindClasses || ''}"
style={`grid-area: ${child.slot}`}
>
{#if child.servicesLoaded}
{#await loadComponentAndService(child) then ChildComponent}
<svelte:component
this={ChildComponent}
id={child.id}
store={getCompositeStore(child.id)}
machine={child.machine}
services={loadedServices}
machineService={child.machineService}
/>
{#if child.children && child.children.length}
<Composite composite={child} />
{/if}
{/await}
{/if}
</div>
{/each}
{/if}
</div>

View File

@ -1,4 +0,0 @@
<script>
export let id;
console.log(`FallBack component rendered with id ${id}`);
</script>

View File

@ -1,10 +0,0 @@
import componentNames from 'virtual:components-list';
const components = {};
componentNames.forEach(path => {
const name = path.split('/').pop(); // Extract just the file name from the path
components[name] = () => import( /* @vite-ignore */ `/src/lib/components/${path}.svelte`);
});
export default components;

View File

@ -1,16 +0,0 @@
import { writable } from 'svelte/store';
const compositeStores = new Map();
// Create or retrieve a composite store
export function createCompositeStore(compositeId: string, initialState = {}) {
if (!compositeStores.has(compositeId)) {
compositeStores.set(compositeId, writable(initialState));
}
return compositeStores.get(compositeId);
}
// Get composite store or create a default empty one if not exists
export function getCompositeStore(compositeId: string) {
return compositeStores.get(compositeId) || createCompositeStore(compositeId);
}

View File

@ -1,23 +0,0 @@
// coreServices.ts
import { getCompositeStore } from './compositeStores';
export const coreServices = {
updateComposite: (mappings: Record<string, string>) => {
for (const [mappingString, value] of Object.entries(mappings)) {
const [storeID, key] = mappingString.replace('@', '').split(':');
const store = getCompositeStore(storeID);
store.update(storeData => {
storeData[key] = value;
return storeData;
});
}
},
subscribeComposite: (mappingString: string) => {
const [storeID] = mappingString.replace('@', '').split(':');
const store = getCompositeStore(storeID);
return store;
},
testAlert: () => {
alert("core service alert")
}
};

View File

@ -1,16 +0,0 @@
// dataLoader.ts
import { writable } from 'svelte/store';
import dataSources from 'virtual:data-sources-list';
// The store that holds the data sets
export const dataStore = writable({});
// Dynamically import the data modules and assign them to the store
dataSources.forEach(src => {
import(`/src/lib/data/${src}.ts`).then(module => {
// Here, explicitly extract the required data or function from the module
const moduleData = module[src] || module.default;
dataStore.update(store => ({ ...store, [src]: moduleData }));
});
});

View File

@ -1,7 +1,7 @@
<script lang="ts">
import { onDestroy } from 'svelte';
import Composer from './Composer.svelte';
import components from '$lib/core/componentLoader';
import components from './componentLoader';
import { createComposerStore, getComposerStore } from './composerStores';
import { coreServices } from './coreServices';
import { Machine, interpret } from 'xstate';
@ -96,6 +96,9 @@
},
{
services: composer.machine.services
},
{
actions: composer.machine.actions
}
);
const machineService = interpret(machine).onTransition((state) => {
@ -115,8 +118,8 @@
return `
grid-template-areas: ${layout.areas};
${layout.gap ? `gap: ${layout.gap};` : ''}
${layout.columns ? `grid-template-columns: ${layout.columns};` : '1fr'}
${layout.rows ? `grid-template-rows: ${layout.rows};` : '1fr'}
${layout.columns ? `grid-template-columns: ${layout.columns};` : ''}
${layout.rows ? `grid-template-rows: ${layout.rows};` : ''}
`;
}

View File

@ -1,15 +0,0 @@
import serviceNames from 'virtual:services-list';
const services: { [key: string]: Function } = {};
serviceNames.forEach(path => {
const serviceName = path.split('/').pop().replace('.ts', '');
services[serviceName] = () => import(/* @vite-ignore */ `/src/lib/services/${path}`)
.then(mod => {
console.log(`Loaded service ${serviceName} with the following properties:`, Object.keys(mod));
if (mod.default) return mod.default;
return mod;
});
});
export default services;

View File

@ -1,12 +0,0 @@
// /lib/stores/contextStore.ts
import { writable } from 'svelte/store';
const createStore = () => writable({});
const contextStore = {};
export const getContextStore = (componentName) => {
if (!contextStore[componentName]) {
contextStore[componentName] = createStore();
}
return contextStore[componentName];
}

View File

@ -7,7 +7,7 @@
import { onMount } from 'svelte';
import { Drawer, drawerStore } from '@skeletonlabs/skeleton';
import Composite from '$lib/core/Composite.svelte';
import Composer from '$lib/core/refactor/Composer.svelte';
const providerData = {
walletConnectId: import.meta.env.VITE_WALLETCONNECT_ID
@ -19,8 +19,9 @@
</script>
<Drawer>
<Composite composite={$drawerStore.meta} />
<Composer composer={$drawerStore.meta} />
</Drawer>
<div class="relative w-screen h-screen overflow-hidden">
<slot />
</div>

View File

@ -1,11 +1,11 @@
<script>
import Composite from '$lib/core/Composite.svelte';
import Composer from '$lib/core/refactor/Composer.svelte';
let composite = {
let composer = {
id: 'login',
component: 'GoogleAuth',
services: ['setupLit']
component: 'GoogleAuth'
// services: ['setupLit']
};
</script>
<Composite {composite} />
<Composer {composer} />

View File

@ -6,75 +6,28 @@
let composer = {
id: 'ComposerParent',
layout: {
columns: '1fr 1fr',
rows: '1fr auto',
areas: `
"left right"
"main"
"bottom"
`
},
children: [
{
id: 'ComposerQueries',
component: 'ComposerQueries',
slot: 'right',
id: 'ComposerOverview',
component: 'ComposerOverview',
slot: 'main',
data: {
map: {
todos: queryTodos,
messages: queryMessages
}
},
machine: {
initial: 'LOADING',
states: {
LOADING: {
on: {
TOGGLE: {
target: 'READY'
}
}
},
READY: {
on: {
TOGGLE: {
target: 'LOADING'
}
}
}
}
}
},
{
id: 'ComposerForm',
component: 'ComposerForm',
slot: 'left',
machine: {
id: 'validation',
initial: 'notValidated',
context: {
isValidated: false
},
states: {
notValidated: {
on: {
VALIDATE: {
target: 'isValidated',
actions: 'setValidated'
}
}
},
isValidated: {
on: {
INVALIDATE: {
target: 'notValidated',
actions: 'setNotValidated'
}
}
}
},
services: {
setValidated: (context) => (context.isValidated = true),
setNotValidated: (context) => (context.isValidated = false)
}
}
id: 'terminal',
component: 'Terminal',
slot: 'bottom'
}
]
};

View File

@ -0,0 +1,59 @@
<script lang="ts">
import Composer from '$lib/core/refactor/Composer.svelte';
import { queryMessages } from '$lib/data/queryMessages';
import { queryTodos } from '$lib/data/queryTodos';
let composer = {
id: 'FormContainer',
layout: {
rows: '1fr auto',
areas: `
"main "
"bottom "
`
},
children: [
{
id: 'ComposerForm',
component: 'ComposerForm',
slot: 'main',
machine: {
id: 'validation',
initial: 'notValidated',
context: {
isValidated: false
},
states: {
notValidated: {
on: {
VALIDATE: {
target: 'isValidated',
actions: 'setValidated'
}
}
},
isValidated: {
on: {
INVALIDATE: {
target: 'notValidated',
actions: 'setNotValidated'
}
}
}
},
services: {
setValidated: (context) => (context.isValidated = true),
setNotValidated: (context) => (context.isValidated = false)
}
}
},
{
id: 'terminal',
component: 'Terminal',
slot: 'bottom'
}
]
};
</script>
<Composer {composer} />

View File

@ -0,0 +1,55 @@
<script lang="ts">
import Composer from '$lib/core/refactor/Composer.svelte';
import { queryMessages } from '$lib/data/queryMessages';
import { queryTodos } from '$lib/data/queryTodos';
let composer = {
id: 'QueriesContainer',
layout: {
rows: '1fr auto',
areas: `
"main"
"bottom"
`
},
children: [
{
id: 'ComposerQueries',
component: 'ComposerQueries',
slot: 'main',
data: {
map: {
todos: queryTodos,
messages: queryMessages
}
},
machine: {
initial: 'LOADING',
states: {
LOADING: {
on: {
TOGGLE: {
target: 'READY'
}
}
},
READY: {
on: {
TOGGLE: {
target: 'LOADING'
}
}
}
}
}
},
{
id: 'terminal',
component: 'Terminal',
slot: 'bottom'
}
]
};
</script>
<Composer {composer} />

View File

@ -0,0 +1,5 @@
<script>
import Recipies from '$lib/components/cleanup/Recipies.svelte';
</script>
<Recipies />

View File

@ -2,7 +2,7 @@
import Composer from '$lib/core/refactor/Composer.svelte';
let composer = {
id: 'ComposerParent',
id: 'StateToStateContainer',
layout: {
rows: '1fr 1fr',
areas: `

View File

@ -1,7 +1,8 @@
<script>
import Composite from '$lib/core/Composite.svelte';
import Composer from '$lib/core/refactor/Composer.svelte';
import { queryMessages } from '$lib/data/queryMessages';
let composite = {
let composer = {
id: 'messages',
layout: {
areas: `
@ -16,9 +17,12 @@
id: 'me',
component: 'Messages',
slot: 'main',
map: { messages: '@data:queryMessages' }
data: {
map: {
messages: queryMessages
}
}
},
{
id: 'terminal',
component: 'Terminal',
@ -28,4 +32,4 @@
};
</script>
<Composite {composite} />
<Composer {composer} />

View File

@ -1,7 +1,7 @@
<script>
import Composite from '$lib/core/Composite.svelte';
import Composer from '$lib/core/refactor/Composer.svelte';
let composite = {
let composer = {
id: 'wallet',
store: {
pkpWallet: '',
@ -43,4 +43,4 @@
};
</script>
<Composite {composite} />
<Composer {composer} />