@jseeio/jsee 0.2.1 → 0.2.5

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/src/app.js CHANGED
@@ -20,12 +20,7 @@ const components = {
20
20
  const filtrex = require('filtrex')
21
21
  const JsonViewer = require('vue3-json-viewer').default
22
22
 
23
- function log () {
24
- console.log(`[Vue]`, ...arguments)
25
- }
26
-
27
23
  function resetInputs (inputs) {
28
- log('Resetting inputs...')
29
24
  inputs.forEach(input => {
30
25
  if (input.default) {
31
26
  input.value = input.default
@@ -65,7 +60,14 @@ function resetInputs (inputs) {
65
60
  })
66
61
  }
67
62
 
68
- function createVueApp (env, dataInit, mountedCallback) {
63
+ function createVueApp (env, mountedCallback, logMain) {
64
+ function log () {
65
+ logMain('[Vue]', ...arguments)
66
+ }
67
+
68
+ // Vue's data is based on schema
69
+ const dataInit = env.schema
70
+
69
71
  // Reset input values to default ones
70
72
  resetInputs(dataInit.inputs)
71
73
 
@@ -73,6 +75,11 @@ function createVueApp (env, dataInit, mountedCallback) {
73
75
  dataInit.outputs = []
74
76
  }
75
77
 
78
+ // Flag that shows if data was changed from initial conditions
79
+ dataInit.dataChanged = false
80
+ // Flag for autorun feedback
81
+ dataInit.clickRun = false
82
+
76
83
  function len(s) {
77
84
  return s.length;
78
85
  }
@@ -142,8 +149,9 @@ function createVueApp (env, dataInit, mountedCallback) {
142
149
  deep: true,
143
150
  immediate: false,
144
151
  handler (v) {
152
+ this.dataChanged = true // Used in the reset button
145
153
  if (this.model.autorun) {
146
- env.run()
154
+ this.run()
147
155
  }
148
156
  }
149
157
  }
@@ -158,9 +166,16 @@ function createVueApp (env, dataInit, mountedCallback) {
158
166
  },
159
167
  reset () {
160
168
  resetInputs(this.inputs)
169
+ this.$nextTick(() => {
170
+ this.dataChanged = false
171
+ })
161
172
  },
162
173
  run () {
174
+ this.clickRun = true
163
175
  env.run()
176
+ setTimeout(() => {
177
+ this.clickRun = false
178
+ }, 150)
164
179
  },
165
180
  notify (msg) {
166
181
  env.notify(msg)
package/src/overlay.js CHANGED
@@ -2,22 +2,7 @@ class Overlay {
2
2
  constructor (parent) {
3
3
  this.element = document.createElement('div')
4
4
  this.element.id = 'overlay'
5
- this.element.className = 'valign-wrapper'
6
- this.element.innerHTML = `
7
- <div class="center-align" style="width:100%">
8
- <div class="preloader-wrapper small active">
9
- <div class="spinner-layer spinner-green-only">
10
- <div class="circle-clipper left">
11
- <div class="circle"></div>
12
- </div><div class="gap-patch">
13
- <div class="circle"></div>
14
- </div><div class="circle-clipper right">
15
- <div class="circle"></div>
16
- </div>
17
- </div>
18
- </div>
19
- </div>
20
- `
5
+ this.element.innerHTML = `...`
21
6
  parent.appendChild(this.element)
22
7
  }
23
8
 
package/src/utils.js ADDED
@@ -0,0 +1,52 @@
1
+ function getModelFuncJS (model, target, log=console.log) {
2
+ switch (model.type) {
3
+ case 'class':
4
+ log('Init class')
5
+ const modelClass = new target()
6
+ return (...a) => {
7
+ return modelClass[model.method || 'predict'](...a)
8
+ }
9
+ case 'async-init':
10
+ // TODO: Test this
11
+ log('Function with async init')
12
+ return target().then(m => {
13
+ log('> Async init resolved: ', m)
14
+ return m
15
+ })
16
+ default:
17
+ log('Init function')
18
+ return target
19
+ }
20
+ }
21
+
22
+ function getModelFuncAPI (model, log=console.log) {
23
+ switch (model.type) {
24
+ case 'get':
25
+ return (data) => {
26
+ const query = new URLSearchParams(data).toString()
27
+ const finalURL = model.url +'?' + query
28
+ log('Sending GET request to:', finalURL)
29
+ const resPromise = fetch(finalURL)
30
+ .then(response => response.json())
31
+ return resPromise
32
+ }
33
+ case 'post':
34
+ return (data) => {
35
+ log('Sending POST request to', this.schema.model.url)
36
+ const resPromise = fetch(this.schema.model.url, {
37
+ method: 'POST',
38
+ headers: {
39
+ 'Accept': 'application/json',
40
+ 'Content-Type': 'application/json'
41
+ },
42
+ body: JSON.stringify(data)
43
+ }).then(response => response.json())
44
+ return resPromise
45
+ }
46
+ }
47
+ }
48
+
49
+ module.exports = {
50
+ getModelFuncJS,
51
+ getModelFuncAPI
52
+ }
package/src/worker.js CHANGED
@@ -1,11 +1,55 @@
1
+ const utils = require('./utils')
2
+
1
3
  function log () {
2
4
  const args = Array.prototype.slice.call(arguments);
3
5
  args.unshift('[Worker]')
4
- console.log(args)
5
6
  postMessage({_status: 'log', _log: args})
6
7
  }
7
8
 
9
+ function initTF (model) {
10
+ throw new Error('Tensorflow in worker (not implemented)')
11
+ }
12
+
13
+ function initPython (model) {
14
+ throw new Error('Python in worker (not implemented)')
15
+ }
16
+
17
+ function initJS (model) {
18
+ log('Init JS')
19
+ this.container = model.container
20
+
21
+ if (model.code) {
22
+ log('Load code as a string')
23
+ // https://github.com/altbdoor/blob-worker/blob/master/blobWorker.js
24
+ importScripts(URL.createObjectURL(new Blob([model.code], { type: 'text/javascript' })))
25
+ } else if (model.url) {
26
+ log('Load script from URL:', model.url)
27
+ importScripts(model.url)
28
+ } else {
29
+ log('No script provided')
30
+ }
31
+
32
+
33
+ // Related:
34
+ // https://stackoverflow.com/questions/37711603/javascript-es6-class-definition-not-accessible-in-window-global
35
+ const target = model.type === 'class'
36
+ ? eval(model.name)
37
+ : this[model.name]
38
+ // Need promise here in case of async init
39
+ Promise.resolve(utils.getModelFuncJS(model, target, log))
40
+ .then(m => {
41
+ postMessage({_status: 'loaded'})
42
+ this.modelFunc = m
43
+ })
44
+ }
45
+
46
+ function initAPI (model) {
47
+ log('Init API')
48
+ this.modelFunc = utils.getModelFuncAPI(model, log)
49
+ }
50
+
8
51
  onmessage = function (e) {
52
+
9
53
  var data = e.data
10
54
  log('Received message of type:', typeof data)
11
55
 
@@ -14,67 +58,30 @@ onmessage = function (e) {
14
58
  INIT MESSAGE
15
59
  */
16
60
  let model = data
61
+ log('Init...')
17
62
 
18
- if (model.type === 'py') {
19
- // Python with Pyodide
20
- importScripts('https://pyodide.cdn.iodide.io/pyodide.js')
21
- // Check when all's loaded
22
- /*
23
- TODO: Implement same loaded as port
24
- let pyCheck = setInterval(() => {
25
- if (self.pyodide && self.pyodide.runPythonAsync && this.model && this.model.length) {
26
- console.log('[Worker] Pyodide lib and model loaded. Try running to preload all imports')
27
- self.pyodide.runPythonAsync(this.model, () => {})
28
- .then((res) => {
29
- postMessage({_status: 'loaded'})
30
- })
31
- .catch((err) => {
32
- postMessage({_status: 'loaded'})
33
- })
34
- clearInterval(pyCheck)
35
- }
36
- }, 500)
37
- */
38
- } else {
39
- // Javascript
40
- this.container = model.container
41
-
42
- if (model.code) {
43
- log('Load code from schema')
44
- // https://github.com/altbdoor/blob-worker/blob/master/blobWorker.js
45
- importScripts(URL.createObjectURL(new Blob([model.code], { type: 'text/javascript' })))
46
- } else if (model.url) {
47
- log('Load script from URL:', model.url)
48
- importScripts(model.url)
49
- } else {
50
- log('No script provided')
51
- }
52
-
53
- if (model.type === 'class') {
54
- log('[Worker] Init class')
55
- // this.modelFunc = (new this[model.name]())[model.method || 'predict']
56
-
57
- const modelClass = new this[model.name]()
58
- this.modelFunc = (...a) => {
59
- return modelClass[model.method || 'predict'](...a)
60
- }
61
- } else if (model.type === 'async-init') {
62
- log('Init function with promise')
63
- log(this[model.name])
64
- this[model.name]().then((m) => {
65
- log('Async init resolved: ', m)
66
- this.modelFunc = m
67
- })
68
- } else {
69
- log('Init function')
70
- this.modelFunc = this[model.name]
71
- }
72
-
73
- postMessage({_status: 'loaded'})
63
+ switch (model.type) {
64
+ case 'tf':
65
+ initTF(model)
66
+ break
67
+ case 'py':
68
+ initPython(model)
69
+ break
70
+ case 'function':
71
+ case 'class':
72
+ case 'async-init':
73
+ case 'async-function':
74
+ initJS(model)
75
+ break
76
+ case 'get':
77
+ case 'post':
78
+ initAPI(model)
79
+ break
74
80
  }
75
81
  } else {
76
82
  /*
77
- CALL MESSAGE
83
+ :w
84
+ CALL MESSAGE
78
85
  */
79
86
  var res
80
87
  if (typeof this.modelFunc === 'string') {
@@ -11,6 +11,95 @@
11
11
  @import "../node_modules/bulma/sass/layout/section.sass";
12
12
 
13
13
  font-family: sans-serif;
14
+
15
+ #overlay {
16
+ display: none;
17
+ position: absolute;
18
+ top: -1px;
19
+ left: -1px;
20
+ right: -1px;
21
+ bottom: -1px;
22
+ background: #F5F5F5;
23
+ opacity: .6;
24
+ z-index: 1000;
25
+ align-items: center;
26
+ justify-content: center;
27
+ }
28
+
29
+
30
+ .card-header {
31
+ box-shadow: none;
32
+ border-bottom: 1px solid #ececec;
33
+ }
34
+
35
+ .card-header-title {
36
+ font-weight: 400;
37
+ }
38
+
39
+ .card-header-title, .card-header-icon {
40
+ padding: 0.75rem 1.5rem;
41
+ cursor: initial;
42
+ }
43
+
44
+ .card-header-icon button {
45
+ border: none;
46
+ margin: 0 0 0 5px;
47
+ padding: 0px 7px;
48
+ height: auto;
49
+
50
+ &:hover {
51
+ background-color: whitesmoke;
52
+ }
53
+ }
54
+
55
+ .card-footer {
56
+ /* background: linear-gradient(62deg, rgba(0,171,209,1) 0%, rgba(0,209,178,1) 100%); */
57
+ background: linear-gradient(90deg, #4395d0 0%, #00d1b2 100%);
58
+ }
59
+
60
+ .card-footer.reset {
61
+ background: linear-gradient(90deg, #ff577f 0%, #4395d0 50%, #00d1b2 100%);
62
+ }
63
+
64
+ .card-footer .button {
65
+ background: none;
66
+ padding: .75rem 1.5rem;
67
+ border: none !important;
68
+ font-size: 14px;
69
+ font-weight: 400;
70
+ border-radius: 0;
71
+ }
72
+
73
+ .reset-button {
74
+ justify-content: left;
75
+ }
76
+
77
+ .reset-button:hover {
78
+ background-color: transparent !important;
79
+ background: linear-gradient(90deg, #ff3a56 0%, #fff0 80%)
80
+ }
81
+
82
+ .card-footer .run-button {
83
+ border-left: 1px dashed white;
84
+ justify-content: right;
85
+ }
86
+
87
+ .card-footer .run-button:hover,{
88
+ background-color: transparent !important;
89
+ background: linear-gradient(270deg, #02dbb2 0%, #fff0 80%);
90
+ }
91
+
92
+ .card-footer .run-button.running .run-icon {
93
+ color: #016c5c !important;
94
+ }
95
+
96
+ .field {
97
+ margin-bottom: 5px;
98
+ }
99
+
100
+ .input, .textarea, .select select {
101
+ border-color: #e8e8e8;
102
+ }
14
103
  }
15
104
  </style>
16
105
  <template>
@@ -25,7 +114,7 @@
25
114
  <div class="columns">
26
115
  <div class="column" v-bind:class="($parent.design && $parent.design.grid && ($parent.design.grid.length > 0)) ? 'is-' + $parent.design.grid[0] : ''">
27
116
  <div class="card bordered">
28
- <div class="card-content" id="inputs">
117
+ <div class="card-content" id="inputs" v-if="$parent.inputs && $parent.inputs.length > 0">
29
118
  <ul>
30
119
  <li v-for="(input, index) in $parent.inputs">
31
120
  <vue-input v-bind:input="input" v-if="$parent.display(index)" v-on:inchange="$parent.run()"></vue-input>
@@ -34,18 +123,24 @@
34
123
  <pre v-if="$parent.model.debug">{{ $parent.inputs }}</pre>
35
124
  <!-- <button class="button is-primary" id="run"><span>▸</span>&nbsp;&nbsp;Run</button> -->
36
125
  </div>
37
- <div class="card">
38
- <footer class="card-footer">
39
- <button v-on:click="$parent.reset()" class="button icon card-footer-item is-danger is-small">
40
- <span class="has-text-danger-dark">✕</span>
41
- <span>&nbsp; Reset</span>
42
- </button>
43
- <button v-on:click="$parent.run()" class="button icon card-footer-item is-primary is-small">
44
- <span class="has-text-primary-dark">▸</span>
45
- <span>&nbsp; Run</span>
46
- </button>
47
- </footer>
48
- </div>
126
+ <footer class="card-footer" v-bind:class="{ reset: $parent.dataChanged }">
127
+ <button
128
+ v-on:click="$parent.reset()"
129
+ v-if="$parent.inputs && $parent.inputs.length > 0 && $parent.dataChanged"
130
+ class="button reset-button icon card-footer-item is-danger is-small"
131
+ >
132
+ <span class="rest-icon has-text-danger-dark">✕</span>
133
+ <span>&nbsp; Reset</span>
134
+ </button>
135
+ <button
136
+ v-on:click="$parent.run()"
137
+ class="button run-button icon card-footer-item is-primary is-small"
138
+ v-bind:class="{ running: $parent.clickRun }"
139
+ >
140
+ <span>&nbsp; Run &nbsp;</span>
141
+ <span class="run-icon has-text-primary-dark">▸</span>
142
+ </button>
143
+ </footer>
49
144
  </div>
50
145
  </div>
51
146
  <div class="column" id="outputs">
@@ -5,8 +5,8 @@
5
5
  {{ output.name }}
6
6
  </p>
7
7
  <p class="card-header-icon">
8
- <button class="button icon is-small" v-on:click="save()">Save</button>
9
- <button class="button icon is-small" v-on:click="copy()">Copy</button>
8
+ <button class="button is-small" v-on:click="save()">Save</button>
9
+ <button class="button is-small" v-on:click="copy()">Copy</button>
10
10
  </p>
11
11
  </header>
12
12
  <div class="card-content">
package/test/code.html ADDED
@@ -0,0 +1,25 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ function sum (a, b) {
6
+ return a + b
7
+ }
8
+ new JSEE({
9
+ schema: {
10
+ "model": {
11
+ "name": "sum",
12
+ "type": "function",
13
+ "container": "args",
14
+ "code": sum,
15
+ "autorun": true,
16
+ "worker": false
17
+ },
18
+ "inputs": [
19
+ { "name": "a", "type": "int", "default": 100 },
20
+ { "name": "b", "type": "int", "default": 42 }
21
+ ]
22
+ }
23
+ })
24
+ </script>
25
+ </html>
@@ -0,0 +1,25 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ function sum (a, b) {
6
+ return a + b
7
+ }
8
+ new JSEE({
9
+ schema: {
10
+ "model": {
11
+ "name": "sum",
12
+ "type": "function",
13
+ "container": "args",
14
+ "code": sum,
15
+ "autorun": true,
16
+ "worker": true
17
+ },
18
+ "inputs": [
19
+ { "name": "a", "type": "int", "default": 100 },
20
+ { "name": "b", "type": "int", "default": 42 }
21
+ ]
22
+ }
23
+ })
24
+ </script>
25
+ </html>
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ class Doubler {
2
+ constructor() {
3
+ this.a = 2
4
+ }
5
+ double(b) {
6
+ return this.a * b
7
+ }
8
+ }
@@ -0,0 +1,3 @@
1
+ function sum (a, b) {
2
+ return a + b
3
+ }
@@ -0,0 +1,14 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ new JSEE({
6
+ schema: {
7
+ 'model': function (a, b) {
8
+ return a * b
9
+ }
10
+ },
11
+ container: 'jsee-container'
12
+ })
13
+ </script>
14
+ </html>
@@ -0,0 +1,26 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+ new JSEE({
6
+ schema: {
7
+ "model": {
8
+ "name": "sum",
9
+ "type": "function",
10
+ "container": "args",
11
+ "code": `
12
+ function sum (a, b) {
13
+ return a + b
14
+ }
15
+ `,
16
+ "autorun": true,
17
+ "worker": false
18
+ },
19
+ "inputs": [
20
+ { "name": "a", "type": "int", "default": 100 },
21
+ { "name": "b", "type": "int", "default": 42 }
22
+ ]
23
+ }
24
+ })
25
+ </script>
26
+ </html>
@@ -0,0 +1,29 @@
1
+ <html>
2
+ <div id="jsee-container">
3
+ <script src="/dist/jsee.js"></script>
4
+ <script>
5
+
6
+ new JSEE({
7
+ schema: {
8
+ "model": {
9
+ "name": "sum",
10
+ "type": "function",
11
+ "container": "args",
12
+ "code": `
13
+ function sum (a, b) {
14
+ return a + b
15
+ }
16
+ `,
17
+ "autorun": true,
18
+ "worker": true
19
+ },
20
+ "inputs": [
21
+ { "name": "a", "type": "int", "default": 100 },
22
+ { "name": "b", "type": "int", "default": 42 }
23
+ ]
24
+ },
25
+ container: '#jsee-container',
26
+ verbose: false
27
+ })
28
+ </script>
29
+ </html>
@@ -0,0 +1,17 @@
1
+ {
2
+ "model": {
3
+ "name": "sum",
4
+ "type": "function",
5
+ "title": "title",
6
+ "description": "description",
7
+ "container": "args",
8
+ "url": "example-sum.js",
9
+ "autorun": true,
10
+ "worker": false
11
+ },
12
+ "inputs": [
13
+ { "name": "a", "type": "int", "default": 100 },
14
+ { "name": "b", "type": "int", "default": 42 }
15
+ ]
16
+ }
17
+
@@ -0,0 +1,17 @@
1
+ {
2
+ "model": {
3
+ "name": "sum",
4
+ "type": "function",
5
+ "title": "title",
6
+ "description": "description",
7
+ "container": "args",
8
+ "url": "example-sum.js",
9
+ "autorun": true,
10
+ "worker": true
11
+ },
12
+ "inputs": [
13
+ { "name": "a", "type": "int", "default": 100 },
14
+ { "name": "b", "type": "int", "default": 42 }
15
+ ]
16
+ }
17
+