Remove old code

This commit is contained in:
Thomas Lovén 2021-03-27 00:36:53 +01:00
parent da9cbbe8a5
commit f9aab2b70e
6 changed files with 2 additions and 887 deletions

View File

@ -1,3 +1,5 @@
import "./hat-graph";
import "./hat-graph-node";
import { HatGraphNode } from "./hat-graph-node"; import { HatGraphNode } from "./hat-graph-node";
import { import {

View File

@ -1,61 +1,8 @@
import { demoConfig2 } from "./demo-config"; import { demoConfig2 } from "./demo-config";
import "@vanillawc/wc-codemirror"; import "@vanillawc/wc-codemirror";
import "./script-graph";
// import "./script-graph3";
import "./hat-graph/hat-graph-node";
import "./hat-graph/hat-graph";
import { makeGraph } from "./hat-graph/make-graph"; import { makeGraph } from "./hat-graph/make-graph";
import { ActionHandler } from "./script-to-graph";
import { mdiAsterisk, mdiArrowUp, mdiArrowDown } from "@mdi/js";
let index_counter = 0;
let nodes = [];
window.onload = () => {
return;
//const graph2 = document.createElement("script-graph3");
//document.querySelector("#graph2").appendChild(graph2);
let src = demoConfig;
const fullcode = document.querySelector("#fullcode");
fullcode.mode = "yaml";
window.setTimeout(() => (fullcode.value = jsyaml.safeDump(src)), 100);
const updateButton = document.querySelector("#updateButton");
updateButton.addEventListener("click", () => {
src = jsyaml.safeLoad(fullcode.value);
index_counter = 0;
nodes = [];
tr.actions = src;
graph.tree = tr.graph;
});
const graph = document.createElement("script-graph");
const tr = new ActionHandler();
window.tr = tr;
tr.actions = src;
tr.updateCallback = (actions) => {
graph.tree = tr.graph;
fullcode.value = jsyaml.safeDump(tr.actions);
};
tr.selectCallback = (idx, action, update) => {
graph.tree = tr.graph;
const code = document.querySelector("#snippet");
code.value = jsyaml.safeDump(action);
document.querySelector("#saveSnippet").onclick = () =>
update(jsyaml.safeLoad(code.value));
document.querySelector("#deleteSnippet").onclick = () =>
update(jsyaml.safeLoad(null));
};
graph.tree = tr.graph;
document.querySelector("#graph").appendChild(graph);
};
function nodeSelected(ev) { function nodeSelected(ev) {
const code = document.querySelector("#snippet"); const code = document.querySelector("#snippet");
code.value = jsyaml.safeDump(ev.detail.config); code.value = jsyaml.safeDump(ev.detail.config);

View File

@ -1,204 +0,0 @@
import {
LitElement,
html,
css,
svg,
property
} from "lit-element";
import { mdiPlus } from "@mdi/js";
const SIZE = 35;
const DIST = 20;
export interface TreeNode {
icon: String;
styles?: String;
end?: Boolean;
children?: (TreeNode | TreeNode[])[];
clickCallback?: any;
addCallback?: any;
}
class ScriptGraph2 extends LitElement {
@property() selected = null;
@property() tree: [TreeNode];
@property() nodeSize = SIZE;
@property() nodeSeparation = DIST;
private _draw_node(x, y, node) {
return svg`
<circle
cx="${x}"
cy="${y + this.nodeSize/2}"
r="${this.nodeSize/2}"
class="node"
@click=${node.clickCallback}
style=${node.styles}
/>
<g style="pointer-events: none" transform="translate(${x - 12} ${y + this.nodeSize/2 - 12})">
<path d="${node.icon}"/>
</g>
`;
}
private _draw_new_node(x, y, node) {
return svg`
<circle
cx="${x}"
cy="${y + this.nodeSize/4}"
r="${this.nodeSize/4}"
class="newnode"
@click=${node.addCallback}
/>
`;
}
private _draw_connector(x1, y1, x2, y2) {
return svg`
<line
x1=${x1}
y1=${y1}
x2=${x2}
y2=${y2}
/>
`;
}
private _draw_tree(tree: TreeNode | TreeNode[]) {
if(!tree) return {svg: `Hello`, width: 0, height: 0};
if(!Array.isArray(tree)) {
let height = this.nodeSize;
let width = this.nodeSize;
let pieces = [];
if(tree.children) {
const childTrees = tree.children.map((c) =>this._draw_tree(c));
height += childTrees.reduce((a,i) => Math.max(a, i.height), 0);
width = childTrees.reduce((a,i) => a+i.width, 0) + this.nodeSeparation*(tree.children.length - 1);
const offsets = childTrees.map((sum => value => sum += value.width + this.nodeSeparation)(0));
let bottomConnectors = false;
for (const [idx, child] of childTrees.entries()) {
const x = -width/2 + (idx? offsets[idx-1] : 0) + child.width/2;
// Draw top connectors
pieces.push(this._draw_connector(
0,
this.nodeSize/2,
x,
this.nodeSize + this.nodeSeparation
));
let endNode = tree.children[idx];
if(Array.isArray(endNode)) endNode = endNode[endNode.length -1];
if(endNode.end !== false) {
// Draw bottom fill
pieces.push(this._draw_connector(
x,
this.nodeSeparation + child.height,
x,
this.nodeSeparation + height
));
// Draw bottom connectors
pieces.push(this._draw_connector(
x,
this.nodeSeparation + height,
0,
this.nodeSeparation + height + this.nodeSize/2 + this.nodeSeparation
));
bottomConnectors = true;
}
// Draw child tree
pieces.push(svg`
<g class="a" transform="translate(${x} ${this.nodeSize + this.nodeSeparation})">
${child.svg}
</g>
`);
}
if(bottomConnectors)
height += this.nodeSize + this.nodeSeparation;
}
if(tree.addCallback) {
pieces.push(this._draw_connector(
0,
height,
0,
height + this.nodeSeparation
));
pieces.push(this._draw_new_node(
0, height + this.nodeSeparation,
tree
));
height += this.nodeSeparation + this.nodeSize/2;
}
if(tree.end !== false) {
// Draw bottom connector
pieces.push(this._draw_connector(
0,
height,
0,
height + this.nodeSeparation
));
height += this.nodeSeparation;
}
// Draw the node itself
pieces.push(this._draw_node(0, 0, tree));
return {svg: pieces, width, height};
}
// Array of trees
let pieces = [];
let height = 0;
const children = tree.map((n) => this._draw_tree(n));
const width = children.reduce((a,i) => Math.max(a, i.width), 0);
for (const [_, node] of children.entries()) {
pieces.push(svg`
<g class="b" transform="translate(0, ${height})">
${node.svg}
</g>
`);
height += node.height;
}
return {svg: pieces, width, height};
}
render() {
let tree = this._draw_tree(this.tree);
return html`
<style>
:host {
--stroke-clr: var(--stroke-color, rgb(3, 169, 244));
--hover-clr: var(--hover-color, rgb(255, 152, 0));
}
circle, line {
stroke: var(--stroke-clr);
stroke-width: 5;
fill: white;
}
.newnode:hover {
stroke: var(--hover-clr);
}
</style>
<svg width=${tree.width + 32} height=${tree.height + 32}>
<g transform="translate(${tree.width/2 + 16} 16)">
${tree.svg}
</g>
</svg>
`;
}
}
customElements.define("script-graph", ScriptGraph2);

View File

@ -1,298 +0,0 @@
import {
LitElement,
html,
css,
svg,
property,
TemplateResult,
} from "lit-element";
import {
mdiCallSplit,
mdiAbTesting,
mdiCheck,
mdiClose,
mdiChevronRight,
mdiExclamation,
mdiTimerOutline,
mdiTrafficLight,
mdiRefresh,
mdiArrowUp,
mdiCodeJson,
mdiCheckBoxOutline,
mdiCheckboxBlankOutline,
mdiAsterisk,
mdiCircleOutline,
} from "@mdi/js";
const ICONS = {
"call-split": mdiCallSplit,
"ab-testing": mdiAbTesting,
check: mdiCheck,
close: mdiClose,
"chevron-right": mdiChevronRight,
exclamation: mdiExclamation,
asterisk: mdiAsterisk,
};
const SIZE = 24;
interface GraphNode extends LitElement {
render_svg(): TemplateResult;
width: number;
height: number;
}
class ScriptGraphNode extends LitElement {
@property() icon = "chevron-right";
connectedCallback() {
super.connectedCallback();
if (!this.hasAttribute("tabindex")) this.setAttribute("tabindex", "0");
}
get width() {
return SIZE + 5;
}
get height() {
return SIZE + 5;
}
render() {
return svg`
<svg
width="${this.width}"
height="${this.height}"
viewBox="${-this.width / 2} 0 ${this.width} ${this.height}"
>
<circle
cx="0"
cy="${this.width / 2}"
r="${SIZE / 2}"
/>
<g
style="pointer-events: none"
transform="translate(${-12} ${this.width / 2 - 12})"
>
${
ICONS[this.icon]
? svg`
<path d="${ICONS[this.icon]}"/>
`
: ""
}
</g>
</svg>
`;
}
static get styles() {
return css`
:host {
display: flex;
--stroke-clr: var(--stroke-color, rgb(3, 169, 244));
--hover-clr: var(--hover-color, rgb(255, 152, 0));
}
circle {
stroke: var(--stroke-clr);
stroke-width: 2;
fill: white;
}
:host(:hover) {
--stroke-clr: var(--hover-clr);
}
:host(:focus) {
--stroke-clr: green;
outline: none;
}
`;
}
}
class ScriptGraphBranch extends LitElement {
@property() _num_items = 0;
@property() _branch_height = 30;
@property() _branch_curve = 25;
get width() {
let w = 0;
for (const c of this.children) {
w += (c as any).width ?? 0;
}
return w;
}
get height() {
let h = 0;
for (const c of this.children) {
h = Math.max(h, (c as any).height ?? 0);
}
return h + 2 * this._branch_height;
}
async updateChildren() {
this._num_items = this.children.length;
}
render() {
let branch_x = [];
let total = 0;
for (const c of Array.from(this.children)) {
const rect = c.getBoundingClientRect();
branch_x.push(rect.width / 2 + total);
total += rect.width;
}
const line_end = this.height - this._branch_height;
return html`
<svg width="${this.width}" height="${this.height}">
<rect
x="0"
y="0"
width="${this.width}"
height="${this.height}"
fill="white"
/>
${branch_x.map((x) => {
return svg`
<path
class="line"
d="
M ${this.width / 2} 0
C ${this.width / 2} ${this._branch_curve}
${x} ${this._branch_height - this._branch_curve}
${x} ${this._branch_height}
L ${x} ${line_end}
C ${x} ${line_end + this._branch_curve}
${this.width / 2} ${this.height - this._branch_curve}
${this.width / 2} ${this.height}
"
/>
`;
})}
</svg>
<script-graph-node id="head" .icon=${"call-split"}> </script-graph-node>
<div id="branches" style="top: ${this._branch_height}px;">
<slot @slotchange=${this.updateChildren}></slot>
</div>
`;
}
static get styles() {
return css`
:host {
position: relative;
display: flex;
--stroke-clr: var(--stroke-color, rgb(3, 169, 244));
--hover-clr: var(--hover-color, rgb(255, 152, 0));
}
#branches {
position: absolute;
top: 20px;
left: 0;
display: flex;
flex-direction: row;
align-items: center;
}
path.line {
stroke: var(--stroke-clr);
stroke-width: 2;
fill: white;
}
#head {
position: Absolute;
top: 5px;
left: 50%;
transform: translate(-50%, -50%);
}
:host(:focus-within) #head {
--stroke-color: green;
}
`;
}
}
class ScriptGraph3 extends LitElement {
@property() content = [];
@property() _width = 0;
@property() _height = 0;
@property() _distance = 20;
async updateChildren() {
return;
}
childrenChangedCallback() {
console.log("Children changed");
}
get height() {
let h = 0;
for (const c of this.children) {
h += (c as any).height ?? 0;
h += this._distance;
}
return h + this._distance;
}
get width() {
let w = 0;
for (const c of this.children) {
w = Math.max(w, (c as any).width ?? 0);
}
return w;
}
render() {
return html`
<svg width="${this.width}" height="${this.height}">
<rect
x="0"
y="0"
width="${this.width}"
height="${this.height}"
fill="white"
/>
<path
class="line"
d="
M ${this.width / 2} 0
L ${this.width / 2} ${this.height}
"
/>
</svg>
<div id="nodes" style="--distance: ${this._distance}px;">
<slot @slotchange=${this.updateChildren}></slot>
</div>
`;
}
static get styles() {
return css`
:host {
position: relative;
display: flex;
--stroke-clr: var(--stroke-color, rgb(3, 169, 244));
--hover-clr: var(--hover-color, rgb(255, 152, 0));
}
#nodes {
position: absolute;
top: var(--distance, 10px);
left: 0;
display: flex;
flex-direction: column;
align-items: center;
}
::slotted(*) {
padding-bottom: var(--distance, 10px);
}
path.line {
stroke: var(--stroke-clr);
stroke-width: 2;
fill: white;
}
`;
}
}
customElements.define("script-graph3", ScriptGraph3);
customElements.define("script-graph-node", ScriptGraphNode);
customElements.define("script-graph-branch", ScriptGraphBranch);

View File

@ -1,262 +0,0 @@
import {
mdiCallSplit,
mdiAbTesting,
mdiCheck,
mdiClose,
mdiChevronRight,
mdiExclamation,
mdiTimerOutline,
mdiTrafficLight,
mdiRefresh,
mdiArrowUp,
mdiCodeJson,
mdiCheckBoxOutline,
mdiCheckboxBlankOutline,
mdiAsterisk,
} from "@mdi/js";
const ICONS = {
new: mdiAsterisk,
service: mdiChevronRight,
condition: mdiAbTesting,
TRUE: mdiCheck,
FALSE: mdiClose,
delay: mdiTimerOutline,
wait_template: mdiTrafficLight,
event: mdiExclamation,
repeat: mdiRefresh,
repeatReturn: mdiArrowUp,
choose: mdiCallSplit,
chooseChoice: mdiCheckBoxOutline,
chooseDefault: mdiCheckboxBlankOutline,
YAML: mdiCodeJson,
};
import { TreeNode} from "./script-graph";
import { Action } from "./types";
const OPTIONS = [
"condition",
"delay",
"device_id",
"event",
"scene",
"service",
"wait_template",
"repeat",
"choose",
];
interface NodeHandler {
(action, selected: any[], select, update): TreeNode;
}
const SPECIAL = {
condition: (action, selected, select, update) => {
return {
icon: ICONS["condition"],
clickCallback: () => select([1], action, update),
children: [
{
icon: ICONS["TRUE"],
clickCallback: () => select([2], action, update),
styles: selected[0]
? "stroke: orange;"
: undefined,
},
{
icon: ICONS["FALSE"],
end: false,
clickCallback: () => select([3], action, update),
styles: selected[0]
? "stroke: orange;"
: undefined,
},
],
}
},
repeat: (action, selected, select, update) => {
let seq = action.repeat.sequence;
if(!seq || !seq.length) seq = [{}];
const seqHandler = new ActionHandler(seq);
if(selected[0] !== undefined && selected[0] !== -1)
seqHandler.selected = selected;
seqHandler.selectCallback = select;
seqHandler.updateCallback = (a) => {
action.repeat["sequence"] = a;
update(action);
}
return {
icon: ICONS["repeat"],
clickCallback: () => select([-1], action, update),
children: [
{
icon: ICONS["repeatReturn"],
clickCallback: () => select([-1], action, update),
styles: selected[0] === -1
? "stroke: orange;"
: undefined,
},
seqHandler.graph,
],
};
},
choose: (action, selected, select, update) => {
let def = action.default || [{}];
const defaultHandler = new ActionHandler(def);
if(selected[0] === -2)
defaultHandler.selected = selected.slice(1);
defaultHandler.selectCallback = (i, a, u) => {
select( [-2].concat(i), a, u);
};
defaultHandler.updateCallback = (a) => {
action.default = defaultHandler.actions;
update(action);
};
return {
icon: ICONS["choose"],
clickCallback: () => select([-1], action, update),
children: [
...action.choose.map((b,idx) => {
const handler = new ActionHandler(b.sequence || [{}]);
if(selected[0] === idx)
handler.selected = selected.slice(1);
handler.selectCallback = (i, a, u) => {
select([idx].concat(i), a, u);
};
handler.updateCallback = (a) => {
b.sequence = handler.actions;
action.choose[idx] = b;
update(action);
};
return [
{
icon: ICONS["chooseChoice"],
clickCallback: () => select([idx], b, (a) => {
action.choose[idx] = a;
update(action);
}),
styles: selected[0] === idx
? "stroke: orange;"
: undefined,
},
handler.graph,
];
}),
[
{
icon: ICONS["chooseDefault"],
clickCallback: () => select([-2], def, (a) => {
action.default = a;
update(action);
}),
styles: selected[0] === -2
? "stroke: orange;"
: undefined,
},
defaultHandler.graph,
]
],
};
},
};
interface NoAction {
}
export class ActionHandler {
_actions: (Action | NoAction)[] = [];
updateCallback = null;
selectCallback = null;
selected: number[] = [];
constructor(actions: (Action | NoAction)[] = []) {
this._actions = actions;
}
set actions(actions) {
this._actions = actions;
}
get actions() {
if(!this._actions.length) this._actions = [{}];
return this._actions;
}
get graph() {
return this.actions.map((action, idx) => this._make_graph_node(idx, action));
}
_update_action(idx: number, action) {
if(action === null)
this.actions.splice(idx, 1);
else
this.actions[idx] = action;
if (this.updateCallback)
this.updateCallback(this.actions);
}
_add_action(idx: number) {
this.actions.splice(idx, 0, {});
if (this.updateCallback)
this.updateCallback(this.actions);
this._select_node([idx], {}, (a) =>this._update_action(idx, a));
}
_select_node(path: number[], action, update=null) {
this.selected = path;
if (this.selectCallback)
this.selectCallback(path, action, update);
}
_make_graph_node(idx: number, action): TreeNode {
let _type = "yaml";
if (Object.keys(action).length === 0)
_type = "new";
else
_type = OPTIONS.find((option) => option in action) || "YAML";
const selected = this.selected.length >= 1 && this.selected[0] == idx;
let node: TreeNode = {icon: ""};
if (_type in SPECIAL) {
node = SPECIAL[_type](
action,
selected ? this.selected.slice(1): [],
(i, a, u) => this._select_node([idx].concat(i), a, u),
(a) => this._update_action(idx, a),
);
} else {
node = {
icon: ICONS[_type],
clickCallback: () => {
this._select_node(
[idx],
action,
(a) => this._update_action(idx, a)
)
}
}
}
return {
...node,
addCallback: () => this._add_action(idx+1),
styles: selected
? "stroke: orange"
: _type === "new"
? "stroke: lightgreen;"
: undefined,
}
}
}

View File

@ -1,70 +0,0 @@
export interface Condition {
condition: string;
}
export interface EventAction {
event: string;
event_data?: { [key: string]: any };
event_data_template?: { [key: string]: any };
}
export interface ServiceAction {
service: string;
entity_id?: string;
data?: { [key: string]: any };
}
export interface DeviceAction {
device_id: string;
domain: string;
entity_id: string;
}
export interface DelayAction {
delay: number;
}
export interface SceneAction {
scene: string;
}
export interface WaitAction {
wait_template: string;
timeout?: number;
}
export interface RepeatAction {
repeat: CountRepeat | WhileRepeat | UntilRepeat;
}
interface BaseRepeat {
sequence: Action[];
}
export interface CountRepeat extends BaseRepeat {
count: number;
}
export interface WhileRepeat extends BaseRepeat {
while: Condition[];
}
export interface UntilRepeat extends BaseRepeat {
until: Condition[];
}
export interface ChooseAction {
choose: [{ conditions: Condition[]; sequence: Action[] }];
default?: Action[];
}
export type Action =
| EventAction
| DeviceAction
| ServiceAction
| Condition
| DelayAction
| SceneAction
| WaitAction
| RepeatAction
| ChooseAction;