@plotinus/matrix-package-observable-coordinator
Version:
Observable coordinator pattern components using IntrospectableBaseCommunicationComponent and proper presentation architecture
198 lines (174 loc) • 6.41 kB
JavaScript
// Component source templates for the coordinator package
export const componentSources = {
// App component sources
appCommunication: `class AppComponent extends window.Matrix.BaseCommunicationComponent {
static dslTag = 'app';
static isMatrixComponent = true;
startExecution() {
console.log(\`App \${this.id} started\`);
this.setState({ status: 'ready' });
}
handleStartProcessing() {
console.log('App: Starting processing');
this.sendCommand('myCoordinator', 'StartProcessing', { jobCount: 5 });
}
handleCoordinatorReady() {
console.log('App: Coordinator is ready, sending StartProcessing command');
this.sendCommand('myCoordinator', 'StartProcessing', { jobCount: 5 });
}
handleCoordinatorDone(data) {
console.log('App: All done!', data);
this.setState({ completedJobs: data.completedJobIds });
}
}`,
appPresentation: `class AppPresentationElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
bindTo(commComponent) {
this.commComponent = commComponent;
this.render();
}
render() {
this.shadowRoot.innerHTML = \`
<style>
:host { display: block; }
.app { border: 2px solid #8b5cf6; padding: 16px; border-radius: 8px; }
button { background: #8b5cf6; color: white; border: none; padding: 8px 16px;
border-radius: 6px; cursor: pointer; }
</style>
<div class="app">
<h3>App: \${this.commComponent?.id}</h3>
<button onclick="this.getRootNode().host.startProcessing()">Start Processing</button>
<slot></slot>
</div>
\`;
}
startProcessing() {
this.commComponent?.handleStartProcessing();
}
}`,
// Coordinator component sources
coordinatorCommunication: `class CoordinatorComponent extends window.Matrix.BaseCommunicationComponent {
static dslTag = 'coordinator';
static isMatrixComponent = true;
constructor(id, eventBus) {
super(id, eventBus);
this.workers = new Set();
this.completedJobs = new Set();
this.jobQueue = [];
}
startExecution() {
this.setState({ status: 'ready' });
this.emitEvent('CoordinatorReady');
}
startProcessingHandler(data) {
console.log('Coordinator: Starting processing');
console.log('Coordinator: Creating jobs');
for (let i = 0; i < (data.jobCount || 5); i++) {
this.jobQueue.push({ id: \`job-\${i + 1}\` });
}
this.distributeJobs();
}
distributeJobs() {
this.workers.forEach(workerId => {
if (this.jobQueue.length > 0) {
const job = this.jobQueue.shift();
this.sendCommand(workerId, 'ProcessJob', job);
}
});
}
handleWorkerRegistered(data) {
this.workers.add(data.workerId);
this.setState({ workerCount: this.workers.size });
}
handleWorkerJobCompleted(data) {
this.completedJobs.add(data.jobId);
if (this.jobQueue.length > 0) {
const job = this.jobQueue.shift();
this.sendCommand(data.workerId, 'ProcessJob', job);
} else if (this.completedJobs.size >= 5) {
this.emitEvent('CoordinatorDone', {
completedJobIds: Array.from(this.completedJobs)
});
}
}
}`,
coordinatorPresentation: `class CoordinatorPresentationElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
bindTo(commComponent) {
this.commComponent = commComponent;
// Subscribe to state changes
if (commComponent.eventBus) {
const stateKey = \`cmp:\${commComponent.id}:_stateChanged\`;
commComponent.eventBus.on(stateKey, () => this.render());
}
this.render();
}
render() {
const state = this.commComponent?.state || {};
this.shadowRoot.innerHTML = \`
<style>
:host { display: block; }
.coordinator { border: 2px solid #58a6ff; padding: 16px; margin: 8px; border-radius: 8px; }
</style>
<div class="coordinator">
<h3>Coordinator: \${this.commComponent?.id}</h3>
<div>Workers: \${state.workerCount || 0}</div>
<slot></slot>
</div>
\`;
}
}`,
// Worker component sources
workerCommunication: `class WorkerComponent extends window.Matrix.BaseCommunicationComponent {
static dslTag = 'worker';
static isMatrixComponent = true;
startExecution() {
this.setState({ jobsProcessed: 0 });
this.emitEvent('Registered', { workerId: this.id });
}
processJobHandler(job) {
console.log(\`Worker \${this.id}: Processing \${job.id}\`);
setTimeout(() => {
this.setState({ jobsProcessed: (this.state.jobsProcessed || 0) + 1 });
this.emitEvent('JobCompleted', {
workerId: this.id,
jobId: job.id
});
}, 1000);
}
}`,
workerPresentation: `class WorkerPresentationElement extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
bindTo(commComponent) {
this.commComponent = commComponent;
// Subscribe to state changes
if (commComponent.eventBus) {
const stateKey = \`cmp:\${commComponent.id}:_stateChanged\`;
commComponent.eventBus.on(stateKey, () => this.render());
}
this.render();
}
render() {
const state = this.commComponent?.state || {};
this.shadowRoot.innerHTML = \`
<style>
:host { display: block; }
.worker { border: 2px solid #3fb950; padding: 12px; margin: 8px; border-radius: 6px; }
</style>
<div class="worker">
<h4>Worker: \${this.commComponent?.id}</h4>
<div>Jobs: \${state.jobsProcessed || 0}</div>
</div>
\`;
}
}`
};