@yarkivaev/simulation-web 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/simulation-web.css +1 -0
- package/dist/simulation-web.js +239 -0
- package/package.json +26 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{margin:0;padding:0;box-sizing:border-box}body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;background:#f4f6f9;color:#333}.app{display:flex;min-height:100vh}.sidebar{width:220px;background:#1e293b;color:#fff;padding:1.5rem 1rem;flex-shrink:0}.logo{font-size:1.2rem;margin-bottom:2rem;padding-bottom:1rem;border-bottom:1px solid #334155}.nav-list{list-style:none}.nav-list li{margin-bottom:.5rem}.nav-list a{color:#94a3b8;text-decoration:none;display:block;padding:.5rem .75rem;border-radius:6px;transition:background .2s,color .2s}.nav-list a:hover,.nav-list a.router-link-active{background:#334155;color:#fff}.content{flex:1;padding:2rem;overflow-y:auto}.editor-container[data-v-ac617ac0]{height:300px;border:1px solid #cbd5e1;border-radius:6px;overflow:hidden}.simulation-control[data-v-0b0ece24]{display:inline-flex;align-items:center;gap:.75rem}.status-badge[data-v-0b0ece24]{padding:.2rem .6rem;border-radius:12px;font-size:.8rem;font-weight:600}.status-badge.RUNNING[data-v-0b0ece24]{background:#dcfce7;color:#166534}.status-badge.STOPPED[data-v-0b0ece24]{background:#f1f5f9;color:#64748b}.btn-primary[data-v-0b0ece24]{background:#3b82f6;color:#fff;border:none;padding:.25rem .75rem;border-radius:6px;cursor:pointer;font-size:.85rem}.btn-danger[data-v-0b0ece24]{background:#ef4444;color:#fff;border:none;padding:.25rem .75rem;border-radius:6px;cursor:pointer;font-size:.85rem}.page-header[data-v-028dcd41]{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.5rem}.data-table[data-v-028dcd41]{width:100%;border-collapse:collapse;background:#fff;border-radius:8px;overflow:hidden;box-shadow:0 1px 3px #0000001a}.data-table th[data-v-028dcd41],.data-table td[data-v-028dcd41]{padding:.75rem 1rem;text-align:left;border-bottom:1px solid #e2e8f0}.data-table th[data-v-028dcd41]{background:#f8fafc;font-weight:600;color:#475569}.dialog-overlay[data-v-028dcd41]{position:fixed;top:0;right:0;bottom:0;left:0;background:#0006;display:flex;align-items:center;justify-content:center;z-index:100}.dialog[data-v-028dcd41]{background:#fff;border-radius:12px;padding:2rem;min-width:400px;box-shadow:0 8px 30px #0000001f}.dialog.wide[data-v-028dcd41]{min-width:700px;max-width:900px}.dialog h2[data-v-028dcd41]{margin-bottom:1.5rem}.dialog label[data-v-028dcd41]{display:block;margin-bottom:1rem;color:#475569}.dialog input[data-v-028dcd41]{display:block;width:100%;margin-top:.25rem;padding:.5rem;border:1px solid #cbd5e1;border-radius:6px}.dialog-actions[data-v-028dcd41]{display:flex;gap:.75rem;justify-content:flex-end;margin-top:1.5rem}.validation[data-v-028dcd41]{padding:.5rem;border-radius:4px;margin-top:.5rem;background:#f0fdf4;color:#15803d}.validation.error[data-v-028dcd41]{background:#fef2f2;color:#dc2626}.btn-primary[data-v-028dcd41]{background:#3b82f6;color:#fff;border:none;padding:.5rem 1.25rem;border-radius:6px;cursor:pointer}.btn-secondary[data-v-028dcd41]{background:#e2e8f0;color:#475569;border:none;padding:.5rem 1.25rem;border-radius:6px;cursor:pointer}.btn-danger[data-v-028dcd41]{background:#ef4444;color:#fff;border:none;padding:.25rem .75rem;border-radius:4px;cursor:pointer;font-size:.85rem;margin-left:.5rem}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { defineComponent as _, resolveComponent as D, openBlock as i, createElementBlock as r, createElementVNode as e, toDisplayString as v, Fragment as b, renderList as g, createVNode as k, withCtx as P, createTextVNode as w, renderSlot as L, ref as p, onMounted as C, watch as O, onBeforeUnmount as x, normalizeClass as V, reactive as B, withModifiers as A, withDirectives as I, vModelText as M, createCommentVNode as $ } from "vue";
|
|
2
|
+
import * as U from "monaco-editor";
|
|
3
|
+
const j = { class: "app" }, z = { class: "sidebar" }, F = { class: "logo" }, G = { class: "nav-list" }, H = { class: "content" }, st = /* @__PURE__ */ _({
|
|
4
|
+
__name: "SimulationLayout",
|
|
5
|
+
props: {
|
|
6
|
+
title: {},
|
|
7
|
+
nav: {}
|
|
8
|
+
},
|
|
9
|
+
setup(t) {
|
|
10
|
+
return (l, a) => {
|
|
11
|
+
const u = D("router-link");
|
|
12
|
+
return i(), r("div", j, [
|
|
13
|
+
e("nav", z, [
|
|
14
|
+
e("h2", F, v(t.title), 1),
|
|
15
|
+
e("ul", G, [
|
|
16
|
+
(i(!0), r(b, null, g(t.nav, (s) => (i(), r("li", {
|
|
17
|
+
key: s.to
|
|
18
|
+
}, [
|
|
19
|
+
k(u, {
|
|
20
|
+
to: s.to
|
|
21
|
+
}, {
|
|
22
|
+
default: P(() => [
|
|
23
|
+
w(v(s.label), 1)
|
|
24
|
+
]),
|
|
25
|
+
_: 2
|
|
26
|
+
}, 1032, ["to"])
|
|
27
|
+
]))), 128))
|
|
28
|
+
])
|
|
29
|
+
]),
|
|
30
|
+
e("main", H, [
|
|
31
|
+
L(l.$slots, "default")
|
|
32
|
+
])
|
|
33
|
+
]);
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}), J = /* @__PURE__ */ _({
|
|
37
|
+
__name: "DslEditor",
|
|
38
|
+
props: {
|
|
39
|
+
modelValue: {}
|
|
40
|
+
},
|
|
41
|
+
emits: ["update:modelValue"],
|
|
42
|
+
setup(t, { emit: l }) {
|
|
43
|
+
const a = t, u = l, s = p();
|
|
44
|
+
let n = null;
|
|
45
|
+
return C(() => {
|
|
46
|
+
s.value && (n = U.editor.create(s.value, {
|
|
47
|
+
value: a.modelValue,
|
|
48
|
+
language: "groovy",
|
|
49
|
+
theme: "vs",
|
|
50
|
+
minimap: { enabled: !1 },
|
|
51
|
+
fontSize: 14,
|
|
52
|
+
lineNumbers: "on",
|
|
53
|
+
scrollBeyondLastLine: !1,
|
|
54
|
+
automaticLayout: !0,
|
|
55
|
+
tabSize: 2
|
|
56
|
+
}), n.onDidChangeModelContent(() => {
|
|
57
|
+
u("update:modelValue", n.getValue());
|
|
58
|
+
}));
|
|
59
|
+
}), O(() => a.modelValue, (f) => {
|
|
60
|
+
n && n.getValue() !== f && n.setValue(f);
|
|
61
|
+
}), x(() => {
|
|
62
|
+
n == null || n.dispose();
|
|
63
|
+
}), (f, y) => (i(), r("div", {
|
|
64
|
+
ref_key: "container",
|
|
65
|
+
ref: s,
|
|
66
|
+
class: "editor-container"
|
|
67
|
+
}, null, 512));
|
|
68
|
+
}
|
|
69
|
+
}), h = (t, l) => {
|
|
70
|
+
const a = t.__vccOpts || t;
|
|
71
|
+
for (const [u, s] of l)
|
|
72
|
+
a[u] = s;
|
|
73
|
+
return a;
|
|
74
|
+
}, R = /* @__PURE__ */ h(J, [["__scopeId", "data-v-ac617ac0"]]), q = { class: "simulation-control" }, K = /* @__PURE__ */ _({
|
|
75
|
+
__name: "SimulationControl",
|
|
76
|
+
props: {
|
|
77
|
+
status: {}
|
|
78
|
+
},
|
|
79
|
+
emits: ["start", "stop"],
|
|
80
|
+
setup(t) {
|
|
81
|
+
return (l, a) => (i(), r("span", q, [
|
|
82
|
+
e("span", {
|
|
83
|
+
class: V(["status-badge", t.status])
|
|
84
|
+
}, v(t.status), 3),
|
|
85
|
+
t.status !== "RUNNING" ? (i(), r("button", {
|
|
86
|
+
key: 0,
|
|
87
|
+
class: "btn-primary btn-sm",
|
|
88
|
+
onClick: a[0] || (a[0] = (u) => l.$emit("start"))
|
|
89
|
+
}, "Start")) : (i(), r("button", {
|
|
90
|
+
key: 1,
|
|
91
|
+
class: "btn-danger btn-sm",
|
|
92
|
+
onClick: a[1] || (a[1] = (u) => l.$emit("stop"))
|
|
93
|
+
}, "Stop"))
|
|
94
|
+
]));
|
|
95
|
+
}
|
|
96
|
+
}), lt = /* @__PURE__ */ h(K, [["__scopeId", "data-v-0b0ece24"]]), d = "/api";
|
|
97
|
+
async function S(t) {
|
|
98
|
+
if (!t.ok)
|
|
99
|
+
throw new Error(`HTTP ${t.status}: ${t.statusText}`);
|
|
100
|
+
return t.json();
|
|
101
|
+
}
|
|
102
|
+
async function Q() {
|
|
103
|
+
return S(await fetch(`${d}/scenarios`));
|
|
104
|
+
}
|
|
105
|
+
async function W(t) {
|
|
106
|
+
return S(await fetch(`${d}/scenarios`, {
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: { "Content-Type": "application/json" },
|
|
109
|
+
body: JSON.stringify(t)
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
async function X(t) {
|
|
113
|
+
await fetch(`${d}/scenarios/${t}`, { method: "DELETE" });
|
|
114
|
+
}
|
|
115
|
+
async function it(t) {
|
|
116
|
+
return S(await fetch(`${d}/scenarios/${t}/validate`, { method: "POST" }));
|
|
117
|
+
}
|
|
118
|
+
async function rt() {
|
|
119
|
+
return S(await fetch(`${d}/simulations`));
|
|
120
|
+
}
|
|
121
|
+
async function ut(t) {
|
|
122
|
+
await fetch(`${d}/simulations/${t}/start`, { method: "POST" });
|
|
123
|
+
}
|
|
124
|
+
async function ct(t) {
|
|
125
|
+
await fetch(`${d}/simulations/${t}/stop`, { method: "POST" });
|
|
126
|
+
}
|
|
127
|
+
async function dt() {
|
|
128
|
+
await fetch(`${d}/simulations/start-all`, { method: "POST" });
|
|
129
|
+
}
|
|
130
|
+
async function mt() {
|
|
131
|
+
await fetch(`${d}/simulations/stop-all`, { method: "POST" });
|
|
132
|
+
}
|
|
133
|
+
const Y = { class: "page-header" }, Z = { class: "data-table" }, tt = ["onClick"], et = ["onClick"], nt = { class: "dialog wide" }, at = /* @__PURE__ */ _({
|
|
134
|
+
__name: "ScenariosPage",
|
|
135
|
+
setup(t) {
|
|
136
|
+
const l = p([]), a = p(!1), u = p(!1), s = p(null), n = B({ name: "", dsl: "" });
|
|
137
|
+
C(async () => {
|
|
138
|
+
l.value = await Q();
|
|
139
|
+
});
|
|
140
|
+
function f(m) {
|
|
141
|
+
n.name = m.name, n.dsl = m.dsl, u.value = !0, a.value = !0;
|
|
142
|
+
}
|
|
143
|
+
function y() {
|
|
144
|
+
a.value = !1, u.value = !1, s.value = null, n.name = "", n.dsl = "";
|
|
145
|
+
}
|
|
146
|
+
async function N() {
|
|
147
|
+
const m = await W({ name: n.name, dsl: n.dsl });
|
|
148
|
+
l.value.push(m), y();
|
|
149
|
+
}
|
|
150
|
+
async function T(m) {
|
|
151
|
+
await X(m), l.value = l.value.filter((o) => o.id !== m);
|
|
152
|
+
}
|
|
153
|
+
return (m, o) => (i(), r("div", null, [
|
|
154
|
+
e("div", Y, [
|
|
155
|
+
o[3] || (o[3] = e("h1", null, "Scenarios", -1)),
|
|
156
|
+
e("button", {
|
|
157
|
+
class: "btn-primary",
|
|
158
|
+
onClick: o[0] || (o[0] = (c) => a.value = !0)
|
|
159
|
+
}, "New Scenario")
|
|
160
|
+
]),
|
|
161
|
+
e("table", Z, [
|
|
162
|
+
o[4] || (o[4] = e("thead", null, [
|
|
163
|
+
e("tr", null, [
|
|
164
|
+
e("th", null, "Name"),
|
|
165
|
+
e("th", null, "Actions")
|
|
166
|
+
])
|
|
167
|
+
], -1)),
|
|
168
|
+
e("tbody", null, [
|
|
169
|
+
(i(!0), r(b, null, g(l.value, (c) => (i(), r("tr", {
|
|
170
|
+
key: c.id
|
|
171
|
+
}, [
|
|
172
|
+
e("td", null, v(c.name), 1),
|
|
173
|
+
e("td", null, [
|
|
174
|
+
e("button", {
|
|
175
|
+
class: "btn-secondary",
|
|
176
|
+
onClick: (E) => f(c)
|
|
177
|
+
}, "Edit", 8, tt),
|
|
178
|
+
e("button", {
|
|
179
|
+
class: "btn-danger",
|
|
180
|
+
onClick: (E) => T(c.id)
|
|
181
|
+
}, "Delete", 8, et)
|
|
182
|
+
])
|
|
183
|
+
]))), 128))
|
|
184
|
+
])
|
|
185
|
+
]),
|
|
186
|
+
a.value ? (i(), r("div", {
|
|
187
|
+
key: 0,
|
|
188
|
+
class: "dialog-overlay",
|
|
189
|
+
onClick: A(y, ["self"])
|
|
190
|
+
}, [
|
|
191
|
+
e("div", nt, [
|
|
192
|
+
e("h2", null, v(u.value ? "Edit" : "New") + " Scenario", 1),
|
|
193
|
+
e("label", null, [
|
|
194
|
+
o[5] || (o[5] = w("Name", -1)),
|
|
195
|
+
I(e("input", {
|
|
196
|
+
"onUpdate:modelValue": o[1] || (o[1] = (c) => n.name = c)
|
|
197
|
+
}, null, 512), [
|
|
198
|
+
[M, n.name]
|
|
199
|
+
])
|
|
200
|
+
]),
|
|
201
|
+
o[6] || (o[6] = e("label", null, "DSL", -1)),
|
|
202
|
+
k(R, {
|
|
203
|
+
modelValue: n.dsl,
|
|
204
|
+
"onUpdate:modelValue": o[2] || (o[2] = (c) => n.dsl = c)
|
|
205
|
+
}, null, 8, ["modelValue"]),
|
|
206
|
+
s.value ? (i(), r("div", {
|
|
207
|
+
key: 0,
|
|
208
|
+
class: V(["validation", { error: !s.value.valid }])
|
|
209
|
+
}, v(s.value.valid ? "Valid" : s.value.error), 3)) : $("", !0),
|
|
210
|
+
e("div", { class: "dialog-actions" }, [
|
|
211
|
+
e("button", {
|
|
212
|
+
class: "btn-secondary",
|
|
213
|
+
onClick: y
|
|
214
|
+
}, "Cancel"),
|
|
215
|
+
e("button", {
|
|
216
|
+
class: "btn-primary",
|
|
217
|
+
onClick: N
|
|
218
|
+
}, "Save")
|
|
219
|
+
])
|
|
220
|
+
])
|
|
221
|
+
])) : $("", !0)
|
|
222
|
+
]));
|
|
223
|
+
}
|
|
224
|
+
}), vt = /* @__PURE__ */ h(at, [["__scopeId", "data-v-028dcd41"]]);
|
|
225
|
+
export {
|
|
226
|
+
R as DslEditor,
|
|
227
|
+
vt as ScenariosPage,
|
|
228
|
+
lt as SimulationControl,
|
|
229
|
+
st as SimulationLayout,
|
|
230
|
+
W as createScenario,
|
|
231
|
+
X as deleteScenario,
|
|
232
|
+
Q as fetchScenarios,
|
|
233
|
+
rt as fetchSimulations,
|
|
234
|
+
dt as startAll,
|
|
235
|
+
ut as startSimulation,
|
|
236
|
+
mt as stopAll,
|
|
237
|
+
ct as stopSimulation,
|
|
238
|
+
it as validateScenario
|
|
239
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yarkivaev/simulation-web",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/simulation-web.js",
|
|
6
|
+
"files": ["dist"],
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "vue-tsc -b && vite build",
|
|
9
|
+
"test": "vitest run --passWithNoTests"
|
|
10
|
+
},
|
|
11
|
+
"peerDependencies": {
|
|
12
|
+
"vue": "^3.5.13",
|
|
13
|
+
"vue-router": "^4.5.0",
|
|
14
|
+
"monaco-editor": "^0.52.2"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@vitejs/plugin-vue": "^5.2.3",
|
|
18
|
+
"monaco-editor": "^0.52.2",
|
|
19
|
+
"typescript": "^5.7.3",
|
|
20
|
+
"vite": "^6.1.1",
|
|
21
|
+
"vitest": "^3.0.5",
|
|
22
|
+
"vue": "^3.5.13",
|
|
23
|
+
"vue-router": "^4.5.0",
|
|
24
|
+
"vue-tsc": "^2.2.8"
|
|
25
|
+
}
|
|
26
|
+
}
|