Skip to content

Commit 66a5de5

Browse files
bump version to 0.0.6 in package.json and package-lock.json; refactor App, SolverGraph, and TimelinesChart classes for improved component structure and event handling
1 parent 3bf7f63 commit 66a5de5

File tree

6 files changed

+118
-38
lines changed

6 files changed

+118
-38
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ratio-gui",
3-
"version": "0.0.5",
3+
"version": "0.0.6",
44
"type": "module",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/app.ts

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
1-
class App {
1+
class App implements AppListener {
2+
3+
private selected_comp: Component<any, HTMLElement> | null = null;
4+
private app_listeners: Set<AppListener> = new Set();
25

36
constructor() { }
7+
8+
get_selected_component(): Component<any, HTMLElement> | null { return this.selected_comp; }
9+
10+
selected_component(component: Component<any, HTMLElement> | null): void {
11+
this.selected_comp = component;
12+
for (const listener of this.app_listeners) { listener.selected_component(component); }
13+
}
14+
15+
add_app_listener(listener: AppListener): void {
16+
this.app_listeners.add(listener);
17+
}
18+
19+
remove_app_listener(listener: AppListener): void {
20+
this.app_listeners.delete(listener);
21+
}
422
}
523

624
export interface AppListener {
@@ -19,11 +37,11 @@ export abstract class Component<P, E extends HTMLElement> {
1937
}
2038

2139
remove(): void {
40+
this.unmounting();
2241
this.element.remove();
23-
this.unmounted();
2442
}
2543

26-
unmounted(): void { }
44+
unmounting(): void { }
2745
}
2846

2947
export abstract class ListComponent<P, E extends HTMLElement, L extends HTMLElement> extends Component<Component<P, E>[], L> {
@@ -60,40 +78,28 @@ export abstract class ListComponent<P, E extends HTMLElement, L extends HTMLElem
6078
} else
6179
throw new Error('Child not found');
6280
}
81+
82+
remove(): void {
83+
for (const child of this.children)
84+
child.remove();
85+
super.remove();
86+
}
6387
}
6488

65-
export class AppComponent extends Component<App, HTMLDivElement> implements AppListener {
89+
export class AppComponent extends Component<App, HTMLDivElement> {
6690

6791
private static instance: AppComponent;
68-
private selected_comp: Component<any, HTMLElement> | null = null;
69-
private app_listeners: Set<AppListener> = new Set();
7092

7193
private constructor() {
7294
super(new App(), document.querySelector('#app') as HTMLDivElement);
7395
this.element.classList.add('d-flex', 'flex-column', 'h-100');
7496
}
7597

7698
static get_instance() {
77-
if (!AppComponent.instance) {
99+
if (!AppComponent.instance)
78100
AppComponent.instance = new AppComponent();
79-
}
80101
return AppComponent.instance;
81102
}
82-
83-
get_selected_component(): Component<any, HTMLElement> | null { return this.selected_comp; }
84-
85-
selected_component(component: Component<any, HTMLElement> | null): void {
86-
this.selected_comp = component;
87-
for (const listener of this.app_listeners) { listener.selected_component(component); }
88-
}
89-
90-
add_app_listener(listener: AppListener): void {
91-
this.app_listeners.add(listener);
92-
}
93-
94-
remove_app_listener(listener: AppListener): void {
95-
this.app_listeners.delete(listener);
96-
}
97103
}
98104

99105
export class AnchorComponent<P> extends Component<P, HTMLAnchorElement> {

src/solver_components.ts

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { AppComponent, Component, AnchorComponent, UListComponent } from './app'
22
import { solver } from "./solver";
33
import { library, icon } from '@fortawesome/fontawesome-svg-core'
44
import { faBrain, faPauseCircle, faPlayCircle, faCheckCircle, faXmarkCircle } from '@fortawesome/free-solid-svg-icons'
5+
import { TimelinesChart } from './solver_timelines';
6+
import { SolverGraph } from './solver_graph';
57

68
library.add(faBrain, faPauseCircle, faPlayCircle, faCheckCircle, faXmarkCircle);
79

@@ -10,7 +12,7 @@ export class SolverAnchor extends AnchorComponent<solver.Solver> implements solv
1012
constructor(solver: solver.Solver) {
1113
super(solver);
1214
solver.add_solver_listener(this);
13-
this.element.addEventListener('click', () => { AppComponent.get_instance().selected_component(this); });
15+
this.element.addEventListener('click', () => { AppComponent.get_instance().payload.selected_component(this); });
1416
}
1517

1618
init(items: Map<string, solver.values.Value>, atoms: Map<number, solver.values.Atom>, state: solver.SolverState, flaws: Map<number, solver.graph.Flaw>, resolvers: Map<number, solver.graph.Resolver>, c_flaw: solver.graph.Flaw | null, c_resolver: solver.graph.Resolver | null): void { this.render(); }
@@ -25,10 +27,10 @@ export class SolverAnchor extends AnchorComponent<solver.Solver> implements solv
2527
this.element.innerHTML = to_icon(this.payload.get_state()) + ' ' + this.payload.get_name();
2628
}
2729

28-
unmounted(): void {
30+
unmounting(): void {
2931
this.payload.remove_solver_listener(this);
30-
if (AppComponent.get_instance().get_selected_component() === this)
31-
AppComponent.get_instance().selected_component(null);
32+
if (AppComponent.get_instance().payload.get_selected_component() === this)
33+
AppComponent.get_instance().payload.selected_component(null);
3234
}
3335
}
3436

@@ -52,9 +54,73 @@ export class SolverListComponent extends UListComponent<solver.Solver> {
5254

5355
export class SolverComponent extends Component<solver.Solver, HTMLDivElement> {
5456

57+
private timelines_chart: TimelinesChart;
58+
private graph_component: SolverGraph;
59+
5560
constructor(solver: solver.Solver) {
5661
super(solver, document.createElement('div'));
57-
this.element.classList.add('flex-grow-1', 'd-flex', 'flex-column');
62+
this.element.classList.add('d-flex', 'flex-column', 'flex-grow-1');
63+
const fragment = document.createDocumentFragment();
64+
const pills = document.createElement('ul');
65+
pills.classList.add('nav', 'nav-pills', 'mb-3');
66+
67+
const timelines_pill = document.createElement('li');
68+
timelines_pill.role = 'presentation';
69+
const timelines_pill_link = document.createElement('a');
70+
timelines_pill_link.classList.add('nav-link', 'active');
71+
timelines_pill_link.id = 'timelines-tab';
72+
timelines_pill_link.setAttribute('data-bs-toggle', 'pill');
73+
timelines_pill_link.setAttribute('data-bs-target', '#slv-' + solver.get_id() + '-timelines');
74+
timelines_pill_link.setAttribute('role', 'tab');
75+
timelines_pill_link.setAttribute('aria-controls', 'timelines');
76+
timelines_pill_link.setAttribute('aria-selected', 'true');
77+
timelines_pill_link.innerText = 'Timelines';
78+
timelines_pill.appendChild(timelines_pill_link);
79+
pills.appendChild(timelines_pill);
80+
81+
const graph_pill = document.createElement('li');
82+
graph_pill.role = 'presentation';
83+
const graph_pill_link = document.createElement('a');
84+
graph_pill_link.classList.add('nav-link');
85+
graph_pill_link.id = 'graph-tab';
86+
graph_pill_link.setAttribute('data-bs-toggle', 'pill');
87+
graph_pill_link.setAttribute('data-bs-target', '#slv-' + solver.get_id() + '-graph');
88+
graph_pill_link.setAttribute('role', 'tab');
89+
graph_pill_link.setAttribute('aria-controls', 'graph');
90+
graph_pill_link.setAttribute('aria-selected', 'false');
91+
graph_pill_link.innerText = 'Graph';
92+
graph_pill.appendChild(graph_pill_link);
93+
pills.appendChild(graph_pill);
94+
95+
fragment.appendChild(pills);
96+
97+
const tab_content = document.createElement('div');
98+
tab_content.classList.add('tab-content');
99+
tab_content.id = 'slv-' + solver.get_id() + '-tab-content';
100+
101+
const timelines = document.createElement('div');
102+
timelines.classList.add('tab-pane', 'fade', 'show', 'active');
103+
timelines.id = 'slv-' + solver.get_id() + '-timelines';
104+
timelines.setAttribute('role', 'tabpanel');
105+
timelines.setAttribute('aria-labelledby', 'timelines-tab');
106+
tab_content.appendChild(timelines);
107+
108+
const graph = document.createElement('div');
109+
graph.classList.add('tab-pane', 'fade');
110+
graph.id = 'slv-' + solver.get_id() + '-graph';
111+
graph.setAttribute('role', 'tabpanel');
112+
graph.setAttribute('aria-labelledby', 'graph-tab');
113+
tab_content.appendChild(graph);
114+
115+
fragment.appendChild(tab_content);
116+
117+
this.timelines_chart = new TimelinesChart(solver);
118+
this.graph_component = new SolverGraph(solver);
119+
}
120+
121+
unmounting(): void {
122+
this.timelines_chart.remove();
123+
this.graph_component.remove();
58124
}
59125
}
60126

src/solver_graph.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import { Component } from "./app";
12
import { solver } from "./solver";
23
import cytoscape from 'cytoscape';
34
import { interpolateRgb } from 'd3-interpolate';
45

56
const costColorScale = interpolateRgb("green", "red");
67
const infiniteColor = "black";
78

8-
export class SolverGraph implements solver.SolverListener {
9+
export class SolverGraph extends Component<solver.Solver, HTMLDivElement> implements solver.SolverListener {
910

1011
cy: cytoscape.Core;
1112
layout = {
@@ -18,8 +19,10 @@ export class SolverGraph implements solver.SolverListener {
1819
};
1920

2021
constructor(solver: solver.Solver) {
22+
super(solver, document.querySelector('#slv-' + solver.get_id() + '-graph') as HTMLDivElement);
23+
this.element.classList.add('d-flex', 'flex-column', 'flex-grow-1');
2124
this.cy = cytoscape({
22-
container: document.getElementById('slv-' + solver.get_id() + '-graph'),
25+
container: this.element,
2326
style: [
2427
{
2528
selector: 'node[type="flaw"]',
@@ -99,6 +102,8 @@ export class SolverGraph implements solver.SolverListener {
99102
current_resolver(resolver: solver.graph.Resolver): void {
100103
this.cy.layout(this.layout).run();
101104
}
105+
106+
unmounting(): void { this.payload.remove_solver_listener(this); }
102107
}
103108

104109
function color(flaw: solver.graph.Flaw | solver.graph.Resolver): string {

src/solver_timelines.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
import { Component } from "./app";
12
import { solver } from "./solver";
23
import Plotly from 'plotly.js';
34

4-
export class TimelinesChart implements solver.SolverListener {
5+
export class TimelinesChart extends Component<solver.Solver, HTMLDivElement> implements solver.SolverListener {
56

6-
private solver: solver.Solver;
77
private layout = {
88
autosize: true,
99
xaxis: { title: 'Time' },
@@ -27,12 +27,13 @@ export class TimelinesChart implements solver.SolverListener {
2727
private config = { responsive: true, displaylogo: false };
2828

2929
constructor(solver: solver.Solver) {
30-
this.solver = solver;
31-
this.solver.add_solver_listener(this);
30+
super(solver, document.querySelector('#slv-' + solver.get_id() + '-timelines') as HTMLDivElement);
31+
this.element.classList.add('d-flex', 'flex-column', 'flex-grow-1');
32+
solver.add_solver_listener(this);
3233
}
3334

3435
init(items: Map<string, solver.values.Value>, atoms: Map<number, solver.values.Atom>, state: solver.SolverState, flaws: Map<number, solver.graph.Flaw>, resolvers: Map<number, solver.graph.Resolver>, c_flaw: solver.graph.Flaw | null, c_resolver: solver.graph.Resolver | null): void {
35-
Plotly.react('slv-' + this.solver.get_id() + '-timelines', [], this.layout, this.config);
36+
Plotly.react(this.element, [], this.layout, this.config);
3637
}
3738

3839
state_changed(state: solver.SolverState): void { }
@@ -41,4 +42,6 @@ export class TimelinesChart implements solver.SolverListener {
4142
current_flaw(flaw: solver.graph.Flaw): void { }
4243
resolver_created(resolver: solver.graph.Resolver): void { }
4344
current_resolver(resolver: solver.graph.Resolver): void { }
45+
46+
unmounting(): void { this.payload.remove_solver_listener(this); }
4447
}

0 commit comments

Comments
 (0)