tranfi 0.0.1
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/LICENSE +21 -0
- package/dist/bundle.js +1 -0
- package/index.html +18 -0
- package/logo.png +0 -0
- package/package.json +68 -0
- package/src/app.css +160 -0
- package/src/app.js +203 -0
- package/src/app.vue +253 -0
- package/src/bulma-input.vue +110 -0
- package/src/common-inputs.js +28 -0
- package/src/main.js +18 -0
- package/src/transforms.js +166 -0
- package/webpack.config.js +108 -0
package/src/app.vue
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
|
|
4
|
+
<it-drawer placement="left" v-model="modalAddTransforms">
|
|
5
|
+
<nav class="panel">
|
|
6
|
+
<!--
|
|
7
|
+
<p class="panel-tabs">
|
|
8
|
+
<a class="is-active">All</a>
|
|
9
|
+
<a>Public</a>
|
|
10
|
+
<a>Private</a>
|
|
11
|
+
</p>
|
|
12
|
+
-->
|
|
13
|
+
<a class="panel-block" v-for="(Transform, i) in transforms" :key="i" @click="addTransform(Transform)">
|
|
14
|
+
<span class="panel-icon">
|
|
15
|
+
<i class="mdi mdi-import" aria-hidden="true" v-if="Transform.type === 'loader'"></i>
|
|
16
|
+
<i class="mdi mdi-shape" aria-hidden="true" v-if="Transform.type === 'parser'"></i>
|
|
17
|
+
<i class="mdi mdi-play-box-outline" aria-hidden="true" v-if="Transform.type === 'output'"></i>
|
|
18
|
+
</span>
|
|
19
|
+
{{ Transform.name }}
|
|
20
|
+
</a>
|
|
21
|
+
</nav>
|
|
22
|
+
</it-drawer>
|
|
23
|
+
|
|
24
|
+
<nav class="mainbar" role="navigation" aria-label="main navigation" style="background: #e6e6e6; position: fixed; width: 100%; top: 0; left: 0; z-index: 100">
|
|
25
|
+
<div class="columns">
|
|
26
|
+
<div class="column is-3 mainbar-left" v-if="!preview">
|
|
27
|
+
<div class="navbar-brand">
|
|
28
|
+
<a class="navbar-item" href="https://tranfi.com">
|
|
29
|
+
<img src="/logo.png" width="112">
|
|
30
|
+
</a>
|
|
31
|
+
|
|
32
|
+
<button class="button is-primary is-outlined" @click="modalAddTransforms = true">
|
|
33
|
+
<span class="icon is-small">
|
|
34
|
+
<i class="mdi mdi-playlist-plus" aria-hidden="true"></i>
|
|
35
|
+
</span>
|
|
36
|
+
</button>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="column mainbar-right" v-bind:class="{ 'is-9': !preview, 'is-12': preview }">
|
|
40
|
+
<div class="navbar-start">
|
|
41
|
+
<div class="navbar-item mainbar-title">
|
|
42
|
+
<span v-if="preview">{{ title }}</span>
|
|
43
|
+
<input class="input" type="text" v-model="title" placeholder="Title..." v-else>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
<div class="navbar-end">
|
|
47
|
+
<div class="navbar-item">
|
|
48
|
+
<div class="buttons">
|
|
49
|
+
<a class="button is-light is-outlined mobile-flexible" v-if="pipeline.length">
|
|
50
|
+
<span class="icon is-small">
|
|
51
|
+
<i class="mdi mdi-content-save" aria-hidden="true"></i>
|
|
52
|
+
</span>
|
|
53
|
+
<span class="desktop-only">
|
|
54
|
+
Save pipeline
|
|
55
|
+
</span>
|
|
56
|
+
</a>
|
|
57
|
+
<a class="button is-light is-outlined preview-button mobile-flexible" @click="preview=true" v-if="!preview">
|
|
58
|
+
<span class="icon is-small">
|
|
59
|
+
<i class="mdi mdi-eye" aria-hidden="true"></i>
|
|
60
|
+
</span>
|
|
61
|
+
<span class="desktop-only">
|
|
62
|
+
View
|
|
63
|
+
</span>
|
|
64
|
+
</a>
|
|
65
|
+
<a class="button is-light is-outlined preview-button mobile-flexible" @click="preview=false" v-if="preview">
|
|
66
|
+
<span class="icon is-small">
|
|
67
|
+
<i class="mdi mdi-pencil" aria-hidden="true"></i>
|
|
68
|
+
</span>
|
|
69
|
+
<span class="desktop-only">
|
|
70
|
+
Edit
|
|
71
|
+
</span>
|
|
72
|
+
</a>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</nav>
|
|
79
|
+
|
|
80
|
+
<div class="columns" style="margin-top: 77px">
|
|
81
|
+
<div class="pipeline column is-3" v-if="!preview">
|
|
82
|
+
|
|
83
|
+
<draggable
|
|
84
|
+
v-model="pipeline"
|
|
85
|
+
@start="drag=true"
|
|
86
|
+
@end="drag=false"
|
|
87
|
+
item-key="id"
|
|
88
|
+
handle=".card-header"
|
|
89
|
+
>
|
|
90
|
+
<template #item="{element}">
|
|
91
|
+
<div>
|
|
92
|
+
<div class="card" v-bind:class="{ active: element.expanded }">
|
|
93
|
+
<header class="card-header">
|
|
94
|
+
<p class="card-header-title">
|
|
95
|
+
{{ element.name }}
|
|
96
|
+
</p>
|
|
97
|
+
<button class="card-header-icon" aria-label="more options" v-on:click="element.expanded = !element.expanded">
|
|
98
|
+
<span class="icon">
|
|
99
|
+
<i class="mdi mdi-chevron-up" aria-hidden="true" v-if="element.expanded"></i>
|
|
100
|
+
<i class="mdi mdi-chevron-down" aria-hidden="true" v-else></i>
|
|
101
|
+
</span>
|
|
102
|
+
</button>
|
|
103
|
+
</header>
|
|
104
|
+
<div class="card-content" >
|
|
105
|
+
<ul>
|
|
106
|
+
<li v-for="(input, index) in element.inputs">
|
|
107
|
+
<vue-input v-bind:input="input"></vue-input>
|
|
108
|
+
</li>
|
|
109
|
+
<li v-if="element.inputs.length">
|
|
110
|
+
<div class="field">
|
|
111
|
+
<label v-bind:for="'disp' + element.id" class="is-size-7">Display on preview:</label>
|
|
112
|
+
<div class="control">
|
|
113
|
+
<div class="select is-multiple">
|
|
114
|
+
<select
|
|
115
|
+
v-model="element.displayInputs"
|
|
116
|
+
v-bind:id="'disp' + element.id"
|
|
117
|
+
multiple
|
|
118
|
+
size="3"
|
|
119
|
+
>
|
|
120
|
+
<option v-for="(input, index) in element.inputs" v-bind:value="index">
|
|
121
|
+
{{ input.name }}
|
|
122
|
+
</option>
|
|
123
|
+
</select>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
</li>
|
|
128
|
+
<li>
|
|
129
|
+
<pre style="font-size: 10px;">{{ element }}</pre>
|
|
130
|
+
</li>
|
|
131
|
+
</ul>
|
|
132
|
+
</div>
|
|
133
|
+
<footer class="card-footer">
|
|
134
|
+
<a class="card-footer-item" @click="cloneTransform(element)">Clone</a>
|
|
135
|
+
<a class="card-footer-item" @click="resetTransform(element)">Reset</a>
|
|
136
|
+
<a class="card-footer-item" @click="deleteTransform(element)">Delete</a>
|
|
137
|
+
</footer>
|
|
138
|
+
</div>
|
|
139
|
+
<p style="text-align: center; font-size: 11px; color: #AAA;">
|
|
140
|
+
<span> ↓ </span>
|
|
141
|
+
<small>{{ element.outputType }}</small>
|
|
142
|
+
</p>
|
|
143
|
+
</div>
|
|
144
|
+
</template>
|
|
145
|
+
</draggable>
|
|
146
|
+
|
|
147
|
+
<button
|
|
148
|
+
@click="modalAddTransforms = true"
|
|
149
|
+
class="button is-primary is-outlined is-fullwidth"
|
|
150
|
+
style="margin-bottom: 10px; min-height: 45px;"
|
|
151
|
+
>
|
|
152
|
+
<span class="icon is-small">
|
|
153
|
+
<i class="mdi mdi-playlist-plus" aria-hidden="true"></i>
|
|
154
|
+
</span>
|
|
155
|
+
<span>
|
|
156
|
+
Add stream
|
|
157
|
+
</span>
|
|
158
|
+
</button>
|
|
159
|
+
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<div class="column preview-content" v-bind:class="{ 'is-9': !preview, 'is-12': preview }">
|
|
163
|
+
|
|
164
|
+
<nav class="breadcrumb has-arrow-separator" aria-label="breadcrumbs">
|
|
165
|
+
<ul>
|
|
166
|
+
<li v-for="transform in pipeline"> {{ transform.name }} </li>
|
|
167
|
+
</ul>
|
|
168
|
+
</nav>
|
|
169
|
+
|
|
170
|
+
<hr v-if="pipeline.length">
|
|
171
|
+
|
|
172
|
+
<nav class="panel preview-panel" v-if="pipeline.length">
|
|
173
|
+
<div class="panel-block" v-for="(input, index) in displayInputs">
|
|
174
|
+
<vue-input v-bind:input="input"></vue-input>
|
|
175
|
+
</div>
|
|
176
|
+
<div class="panel-block" v-if="pipeline.length">
|
|
177
|
+
<button class="button is-primary is-outlined is-fullwidth" @click="run(true)">
|
|
178
|
+
<span class="icon is-small">
|
|
179
|
+
<i class="mdi mdi-play-pause" aria-hidden="true"></i>
|
|
180
|
+
</span>
|
|
181
|
+
<span>
|
|
182
|
+
Load batch
|
|
183
|
+
</span>
|
|
184
|
+
</button>
|
|
185
|
+
</div>
|
|
186
|
+
<div class="panel-block" v-if="pipeline.length">
|
|
187
|
+
<button class="button is-primary is-large is-fullwidth" @click="run(false)">
|
|
188
|
+
<span class="icon is-small">
|
|
189
|
+
<i class="mdi mdi-play" aria-hidden="true"></i>
|
|
190
|
+
</span>
|
|
191
|
+
<span>
|
|
192
|
+
Load all
|
|
193
|
+
</span>
|
|
194
|
+
</button>
|
|
195
|
+
</div>
|
|
196
|
+
</nav>
|
|
197
|
+
|
|
198
|
+
<hr v-if="pipeline.length">
|
|
199
|
+
|
|
200
|
+
<pre id="text-output" style="display: none;"></pre>
|
|
201
|
+
|
|
202
|
+
<hr v-if="pipeline.length && (!loadedAllData)">
|
|
203
|
+
|
|
204
|
+
<nav class="panel preview-panel" v-if="pipeline.length && (!loadedAllData)">
|
|
205
|
+
<div class="panel-block" v-if="pipeline.length">
|
|
206
|
+
<button class="button is-primary is-outlined is-fullwidth" @click="runMore">
|
|
207
|
+
<span class="icon is-small">
|
|
208
|
+
<i class="mdi mdi-play-pause" aria-hidden="true"></i>
|
|
209
|
+
</span>
|
|
210
|
+
<span>
|
|
211
|
+
Load more
|
|
212
|
+
</span>
|
|
213
|
+
</button>
|
|
214
|
+
</div>
|
|
215
|
+
</nav>
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
<!--
|
|
219
|
+
<it-tag>Neutral</it-tag><it-tag>Neutral</it-tag><it-tag>Neutral</it-tag><it-tag>Neutral</it-tag>
|
|
220
|
+
<it-button @click="showMessage('Warning')" type="warning">Warning message</it-button>
|
|
221
|
+
<it-tabs box style="flex: 1">
|
|
222
|
+
<it-tab title="Tab 1">First tab</it-tab>
|
|
223
|
+
<it-tab title="Tab 2">Second tab</it-tab>
|
|
224
|
+
<it-tab title="Tab 3" :disabled="disabledTab">Third tab</it-tab>
|
|
225
|
+
</it-tabs>
|
|
226
|
+
-->
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<!--
|
|
231
|
+
<nav class="bottombar" role="navigation" style="background: none; position: fixed; width: 100%; bottom: 0; left: 0; z-index: 100">
|
|
232
|
+
<div class="columns">
|
|
233
|
+
<div class="column is-3" v-if="!preview"></div>
|
|
234
|
+
<div class="column bottombar-right" v-bind:class="{ 'is-9': !preview, 'is-12': preview }" style="">
|
|
235
|
+
<div class="buttons" v-if="pipeline.length">
|
|
236
|
+
<button class="button is-primary" @click="run">
|
|
237
|
+
<span class="icon is-small">
|
|
238
|
+
<i class="mdi mdi-subdirectory-arrow-right" aria-hidden="true"></i>
|
|
239
|
+
</span>
|
|
240
|
+
<span>
|
|
241
|
+
Run
|
|
242
|
+
</span>
|
|
243
|
+
</button>
|
|
244
|
+
</div>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
</nav>
|
|
248
|
+
-->
|
|
249
|
+
|
|
250
|
+
</div>
|
|
251
|
+
</template>
|
|
252
|
+
<style src="./app.css"></style>
|
|
253
|
+
<script src="./app.js" scoped></script>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="field" v-if="input.type == 'int' || input.type == 'float' || input.type == 'number'">
|
|
3
|
+
<label v-bind:for="input.name" class="is-size-7">{{ input.name }}</label>
|
|
4
|
+
<div class="control">
|
|
5
|
+
<input
|
|
6
|
+
v-model="input.value"
|
|
7
|
+
v-bind:id="input.name"
|
|
8
|
+
v-bind:step="input.type == 'int' ? 1 : 0.001"
|
|
9
|
+
v-bind:placeholder="input.placeholder ? input.placeholder : input.name"
|
|
10
|
+
v-bind:min="input.min"
|
|
11
|
+
v-bind:max="input.max"
|
|
12
|
+
v-on:change="changeHandler"
|
|
13
|
+
class="input"
|
|
14
|
+
type="number"
|
|
15
|
+
>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="field" v-if="input.type == 'string' || input.type == 'color'">
|
|
20
|
+
<label v-bind:for="input.name" class="is-size-7">{{ input.name }}</label>
|
|
21
|
+
<div class="control">
|
|
22
|
+
<input
|
|
23
|
+
v-model="input.value"
|
|
24
|
+
v-bind:id="input.name"
|
|
25
|
+
v-bind:placeholder="input.placeholder ? input.placeholder : input.name"
|
|
26
|
+
v-on:change="changeHandler"
|
|
27
|
+
class="input"
|
|
28
|
+
>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<div class="field" v-if="input.type == 'text'">
|
|
33
|
+
<label v-bind:for="input.name" class="is-size-7">{{ input.name }}</label>
|
|
34
|
+
<div class="control">
|
|
35
|
+
<textarea
|
|
36
|
+
v-model="input.value"
|
|
37
|
+
v-bind:id="input.name"
|
|
38
|
+
v-bind:placeholder="input.placeholder ? input.placeholder : input.name"
|
|
39
|
+
v-on:change="changeHandler"
|
|
40
|
+
class="textarea"
|
|
41
|
+
></textarea>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="field" v-if="input.type == 'checkbox' || input.type == 'bool'">
|
|
46
|
+
<div class="control">
|
|
47
|
+
<label class="checkbox is-size-7">
|
|
48
|
+
<input
|
|
49
|
+
v-model="input.value"
|
|
50
|
+
v-bind:id="input.name"
|
|
51
|
+
v-on:change="changeHandler"
|
|
52
|
+
type="checkbox"
|
|
53
|
+
>
|
|
54
|
+
{{ input.name }}
|
|
55
|
+
</label>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
|
|
59
|
+
<div class="field" v-if="input.type == 'categorical' || input.type == 'select'">
|
|
60
|
+
<label v-bind:for="input.name" class="is-size-7">{{ input.name }}</label>
|
|
61
|
+
<div class="control">
|
|
62
|
+
<div class="select is-fullwidth">
|
|
63
|
+
<select
|
|
64
|
+
v-model="input.value"
|
|
65
|
+
v-bind:id="input.name"
|
|
66
|
+
v-on:change="changeHandler"
|
|
67
|
+
>
|
|
68
|
+
<option
|
|
69
|
+
v-for="(option, oi) in input.options"
|
|
70
|
+
>{{ option }}</option>
|
|
71
|
+
</select>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div class="field" v-if="input.type == 'file'">
|
|
77
|
+
<label v-bind:for="input.name" class="is-size-7">{{ input.name }}</label>
|
|
78
|
+
<div class="control">
|
|
79
|
+
<div class="file has-name is-fullwidth" v-bind:class="{ 'is-primary': !input.file }">
|
|
80
|
+
<label class="file-label">
|
|
81
|
+
<input
|
|
82
|
+
v-bind:id="input.name"
|
|
83
|
+
v-on:change="loadFile"
|
|
84
|
+
class="file-input"
|
|
85
|
+
type="file"
|
|
86
|
+
>
|
|
87
|
+
<span class="file-cta">
|
|
88
|
+
<span class="file-label">
|
|
89
|
+
Open
|
|
90
|
+
</span>
|
|
91
|
+
</span>
|
|
92
|
+
<span class="file-name">
|
|
93
|
+
<span v-if="input.file && input.file.name">{{ input.file.name }}</span>
|
|
94
|
+
<span v-else>No file selected</span>
|
|
95
|
+
</span>
|
|
96
|
+
</label>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div class="field is-horizontal" v-if="input.type == 'group'">
|
|
102
|
+
<div class="field-body">
|
|
103
|
+
<vue-input v-for="(el, index) in input.elements" v-bind:input="el" ></vue-input>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</template>
|
|
107
|
+
|
|
108
|
+
<script>
|
|
109
|
+
export { component as default } from "./common-inputs.js"
|
|
110
|
+
</script>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const FileReader = window['FileReader']
|
|
2
|
+
|
|
3
|
+
const component = {
|
|
4
|
+
props: ['input'],
|
|
5
|
+
emits: ['inchange'],
|
|
6
|
+
methods: {
|
|
7
|
+
changeHandler () {
|
|
8
|
+
if (this.input.reactive) {
|
|
9
|
+
this.$emit('inchange')
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
loadFile (e) {
|
|
13
|
+
const reader = new FileReader()
|
|
14
|
+
this.input.file = e.target.files[0]
|
|
15
|
+
// reader.readAsText(this.input.file)
|
|
16
|
+
// reader.onload = () => {
|
|
17
|
+
// this.input.value = reader.result
|
|
18
|
+
// if (typeof this.input.cb !== 'undefined') {
|
|
19
|
+
// this.input.cb.run()
|
|
20
|
+
// } else if (this.input.reactive) {
|
|
21
|
+
// this.$emit('inchange')
|
|
22
|
+
// }
|
|
23
|
+
// }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export { component }
|
package/src/main.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
|
|
3
|
+
import App from './app.vue'
|
|
4
|
+
|
|
5
|
+
import Equal from 'equal-vue'
|
|
6
|
+
import 'equal-vue/dist/style.css'
|
|
7
|
+
|
|
8
|
+
import bulmaInput from './bulma-input.vue'
|
|
9
|
+
import draggable from 'vuedraggable'
|
|
10
|
+
|
|
11
|
+
const app = createApp(App)
|
|
12
|
+
app.use(Equal)
|
|
13
|
+
|
|
14
|
+
app.component('vue-input', bulmaInput)
|
|
15
|
+
app.component('draggable', draggable)
|
|
16
|
+
|
|
17
|
+
app.mount('#tranfi-container')
|
|
18
|
+
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const ReadStream = require('filestream').read
|
|
2
|
+
const ParseStream = require('csv-parse')
|
|
3
|
+
const JSONStream = require('JSONStream')
|
|
4
|
+
const HTTPStream = require('stream-http')
|
|
5
|
+
const through2 = require('through2')
|
|
6
|
+
|
|
7
|
+
let FileLoader = class FileLoader {
|
|
8
|
+
static inputType = 'text'
|
|
9
|
+
|
|
10
|
+
static outputType = 'text'
|
|
11
|
+
|
|
12
|
+
static type = 'loader'
|
|
13
|
+
|
|
14
|
+
static initStream (params) {
|
|
15
|
+
const stream = new ReadStream(params['File'], {chunkSize: params['Chunk size']})
|
|
16
|
+
stream.setEncoding('utf8')
|
|
17
|
+
// if (params['Encoding'] === 'UTF-8') {}
|
|
18
|
+
return stream
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
constructor (id) {
|
|
22
|
+
this.name = this.constructor.name
|
|
23
|
+
this.inputs = [
|
|
24
|
+
{ name: 'File', type: 'file' },
|
|
25
|
+
// { name: 'Encoding', type: 'categorical', options: ['UTF-8', 'Buffer'], default: 'UTF-8' },
|
|
26
|
+
{ name: 'Chunk size', type: 'int', default: 10000 },
|
|
27
|
+
]
|
|
28
|
+
this.inputType = this.constructor.inputType
|
|
29
|
+
this.outputType = this.constructor.outputType
|
|
30
|
+
this.id = id
|
|
31
|
+
this.expanded = false
|
|
32
|
+
this.displayInputs = [0]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let HTTPLoader = class HTTPLoader {
|
|
37
|
+
static inputType = 'text'
|
|
38
|
+
|
|
39
|
+
static outputType = 'text'
|
|
40
|
+
|
|
41
|
+
static type = 'loader'
|
|
42
|
+
|
|
43
|
+
static initStream (params) {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
HTTPStream.get(params['URL'], function (stream) {
|
|
46
|
+
stream.setEncoding('utf8')
|
|
47
|
+
// if (params['Encoding'] === 'UTF-8') {}
|
|
48
|
+
// stream.setEncoding(params['Encoding'] === 'UTF-8' ? 'utf8' : 'buffer')
|
|
49
|
+
resolve(stream)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
constructor (id) {
|
|
55
|
+
this.name = this.constructor.name
|
|
56
|
+
this.inputs = [
|
|
57
|
+
{ name: 'URL', type: 'string' },
|
|
58
|
+
// { name: 'Encoding', type: 'categorical', options: ['UTF-8', 'Buffer'], default: 'UTF-8' },
|
|
59
|
+
]
|
|
60
|
+
this.inputType = this.constructor.inputType
|
|
61
|
+
this.outputType = this.constructor.outputType
|
|
62
|
+
this.id = id
|
|
63
|
+
this.expanded = false
|
|
64
|
+
this.displayInputs = [0]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let CSVParser = class CSVParser {
|
|
69
|
+
static inputType = 'text'
|
|
70
|
+
|
|
71
|
+
static outputType = 'object'
|
|
72
|
+
|
|
73
|
+
static type = 'parser'
|
|
74
|
+
|
|
75
|
+
static initStream (params) {
|
|
76
|
+
const stream = ParseStream({
|
|
77
|
+
'delimiter': params['Delimiter'],
|
|
78
|
+
'cast': true,
|
|
79
|
+
'columns': true,
|
|
80
|
+
'comment': '#',
|
|
81
|
+
'trim': params['Trim'],
|
|
82
|
+
'relax_column_count': true,
|
|
83
|
+
'skip_empty_lines': params['Skip empty lines'],
|
|
84
|
+
'skip_lines_with_error': true
|
|
85
|
+
})
|
|
86
|
+
return stream
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
constructor (id) {
|
|
90
|
+
this.name = this.constructor.name
|
|
91
|
+
this.inputs = [
|
|
92
|
+
{ name: 'Delimiter', type: 'string', default: ',' },
|
|
93
|
+
{ name: 'Trim', type: 'bool', default: true },
|
|
94
|
+
{ name: 'Skip empty lines', type: 'bool', default: true }
|
|
95
|
+
]
|
|
96
|
+
this.inputType = this.constructor.inputType
|
|
97
|
+
this.outputType = this.constructor.outputType
|
|
98
|
+
this.id = id
|
|
99
|
+
this.expanded = false
|
|
100
|
+
this.displayInputs = []
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let JSONParser = class JSONParser {
|
|
105
|
+
static inputType = 'text'
|
|
106
|
+
|
|
107
|
+
static outputType = 'object'
|
|
108
|
+
|
|
109
|
+
static type = 'parser'
|
|
110
|
+
|
|
111
|
+
static initStream (params) {
|
|
112
|
+
const stream = JSONStream.parse(params['Path'])
|
|
113
|
+
return stream
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
constructor (id) {
|
|
117
|
+
this.name = this.constructor.name
|
|
118
|
+
this.inputs = [
|
|
119
|
+
{ name: 'Path', type: 'string', default: '*' },
|
|
120
|
+
]
|
|
121
|
+
this.inputType = this.constructor.inputType
|
|
122
|
+
this.outputType = this.constructor.outputType
|
|
123
|
+
this.id = id
|
|
124
|
+
this.expanded = false
|
|
125
|
+
this.displayInputs = []
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
let TextOutput = class TextOutput {
|
|
130
|
+
static inputType = 'text'
|
|
131
|
+
|
|
132
|
+
static outputType = 'html'
|
|
133
|
+
|
|
134
|
+
static type = 'output'
|
|
135
|
+
|
|
136
|
+
static initStream (params) {
|
|
137
|
+
const textOutput = document.getElementById('text-output')
|
|
138
|
+
textOutput.style.display = 'block'
|
|
139
|
+
textOutput.innerText = ''
|
|
140
|
+
const stream = through2(function (chunk, enc, callback) {
|
|
141
|
+
textOutput.innerText += chunk
|
|
142
|
+
this.push(chunk)
|
|
143
|
+
callback()
|
|
144
|
+
})
|
|
145
|
+
return stream
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
constructor (id) {
|
|
149
|
+
this.name = this.constructor.name
|
|
150
|
+
this.inputs = []
|
|
151
|
+
this.inputType = this.constructor.inputType
|
|
152
|
+
this.outputType = this.constructor.outputType
|
|
153
|
+
this.id = id
|
|
154
|
+
this.expanded = false
|
|
155
|
+
this.displayInputs = []
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
module.exports = {
|
|
159
|
+
FileLoader,
|
|
160
|
+
HTTPLoader,
|
|
161
|
+
CSVParser,
|
|
162
|
+
JSONParser,
|
|
163
|
+
TextOutput
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const { VueLoaderPlugin } = require('vue-loader') // Support Vue's SFCs
|
|
3
|
+
const TerserPlugin = require('terser-webpack-plugin') // Minimize code
|
|
4
|
+
const webpack = require('webpack')
|
|
5
|
+
const package = require('./package.json')
|
|
6
|
+
|
|
7
|
+
module.exports = (env) => {
|
|
8
|
+
const config = {
|
|
9
|
+
entry: './src/main.js',
|
|
10
|
+
output: {
|
|
11
|
+
filename: 'bundle.js',
|
|
12
|
+
path: path.resolve(__dirname, 'dist'),
|
|
13
|
+
},
|
|
14
|
+
module: {
|
|
15
|
+
rules: [
|
|
16
|
+
{
|
|
17
|
+
test: /\.vue$/,
|
|
18
|
+
loader: 'vue-loader'
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
test: /\.js$/,
|
|
22
|
+
loader: 'babel-loader'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
test: /\.mjs$/i, // lodash error (element)
|
|
26
|
+
resolve: { byDependency: { esm: { fullySpecified: false } } }
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
test: /\.html/,
|
|
30
|
+
type: 'asset/source'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
test: /\.css$/,
|
|
34
|
+
use: [
|
|
35
|
+
'vue-style-loader',
|
|
36
|
+
'css-loader',
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
test: /worker\.js$/,
|
|
41
|
+
loader: "worker-loader",
|
|
42
|
+
options: {
|
|
43
|
+
inline: 'no-fallback'
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
test: /\.scss$/,
|
|
48
|
+
use: [
|
|
49
|
+
'vue-style-loader',
|
|
50
|
+
'css-loader',
|
|
51
|
+
'sass-loader'
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
plugins: [
|
|
57
|
+
new VueLoaderPlugin(),
|
|
58
|
+
// Replace those values in the code
|
|
59
|
+
new webpack.DefinePlugin({
|
|
60
|
+
'VERSION': JSON.stringify(package.version),
|
|
61
|
+
}),
|
|
62
|
+
// https://stackoverflow.com/a/68723223/2998960
|
|
63
|
+
// Work around for Buffer is undefined:
|
|
64
|
+
// https://github.com/webpack/changelog-v5/issues/10
|
|
65
|
+
new webpack.ProvidePlugin({
|
|
66
|
+
Buffer: ['buffer', 'Buffer'],
|
|
67
|
+
}),
|
|
68
|
+
new webpack.ProvidePlugin({
|
|
69
|
+
process: 'process/browser',
|
|
70
|
+
}),
|
|
71
|
+
],
|
|
72
|
+
// Load different versions of vue based on RUNTIME value
|
|
73
|
+
resolve: {
|
|
74
|
+
fallback: {
|
|
75
|
+
'buffer': require.resolve('buffer'),
|
|
76
|
+
'stream': require.resolve('stream-browserify'),
|
|
77
|
+
'url': require.resolve('url')
|
|
78
|
+
},
|
|
79
|
+
alias: {
|
|
80
|
+
vue$: 'vue/dist/vue.runtime.esm-bundler.js'
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
// Update recommended size limit
|
|
84
|
+
performance: {
|
|
85
|
+
hints: false,
|
|
86
|
+
maxEntrypointSize: 512000,
|
|
87
|
+
maxAssetSize: 512000
|
|
88
|
+
},
|
|
89
|
+
// Remove comments
|
|
90
|
+
optimization: {
|
|
91
|
+
minimize: true,
|
|
92
|
+
minimizer: [new TerserPlugin({
|
|
93
|
+
extractComments: false,
|
|
94
|
+
terserOptions: {
|
|
95
|
+
format: {
|
|
96
|
+
comments: false,
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
})],
|
|
100
|
+
},
|
|
101
|
+
// Source map
|
|
102
|
+
devtool: env.DEVELOPMENT
|
|
103
|
+
? 'eval-source-map'
|
|
104
|
+
: false
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return config
|
|
108
|
+
}
|