-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathvue.config.js
258 lines (248 loc) · 10.9 KB
/
vue.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
const path = require('path')
const fs = require('fs')
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser')
module.exports = {
lintOnSave: false,
runtimeCompiler: true,
parallel: false,
css: {
extract: true,
},
configureWebpack: {
resolve: {
modules: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'public'),
// path.resolve(__dirname, 'node_modules'),
],
},
module: {
rules: [
{
test: require('path').resolve(__dirname, 'node_modules/leader-line/'),
use: [{
loader: 'skeleton-loader',
options: {procedure: content => `${content}export default LeaderLine`}
}]
}
]
}
},
devServer: {
before(app) {
//webpack dev server doesn't accept posts by default but we want stub routes for testing
//https://stackoverflow.com/questions/47442543/how-do-i-get-webpack-dev-server-to-accept-post-requests
const bodyParser = require('body-parser')
app.use(cookieParser())
// use bodyParser for axios request
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
/**
* Mock the flowjs-2.0.0 backend GET route to mimic the upload result format:
* {
* 'audio_file_id': 147,
* 'duration_seconds': '4.803250',
* 'description': 'xyz.wav',
* 'created_at': {
* 'date': '2020-11-24 01:41:58',
* 'timezone_type': 3,
* 'timezone': 'UTC'
* },
* 'audio_uuid': '5fbc64e0c74e90.82972899',
* 'uri': 'some_uri_value',
* }
* We can find a server implementation sample from:
* - https://github.com/flowjs/flow-php-server
* - https://packagist.org/packages/flowjs/flow-php-server
*/
app.get('/audiofiles/upload', (req, res) => {
// Simulate `unknown upload chunk` with 404 status for GET method
res.writeHead(404, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({status: 'error', status_description: 'Unknown upload chunk'}))
})
/**
* Mock the flowjs-2.0.0 backend POST route
* Note, flowjs sends form-data as payload.
* We can find a server implementation sample from:
* - https://github.com/flowjs/flow-php-server
* - https://packagist.org/packages/flowjs/flow-php-server
*/
app.post('/audiofiles/upload', bodyParser.json(), (req, res) => {
const now = new Date()
.toISOString()
.split('T')
const audio_uuid = `${Math.random()
.toString(36)
.substr(2, 16)}.${Math.random()
.toString(36)
.substr(2, 10)}`
// TODO (Nice to have): replace original_extension with `req.body.flowFilename.split('.').pop()` when we know how to parse form-data from POST request
const original_extension = 'ogg'
const result = {
audio_file_id: Math.floor(Math.random() * (1000 + 1)),
duration_seconds: Math.random() * 10,
// TODO (Nice to have): replace description with `a description for ${req.body.flowFilename}` when we know how to parse form-data from POST request
description: `{a description from backend}`,
created_at: {
date: `${now[0]} ${now[1].split('.')[0]}`,
timezone_type: 3,
timezone: 'UTC',
},
audio_uuid,
uri: `https://your-domain/path/to/${audio_uuid}.${original_extension}`,
}
// wait a while just to see the status in UI
setTimeout(function(){
res.writeHead(200, {'Content-Type': 'application/json'})
res.end(JSON.stringify(result))
}, 2000)
})
// Returns a flow container. The first flow is the active flow.
// (Other flows are there because they are nested in this first flow
// ...and referenced by UUID I think)
app.get('/backend/flows/:id', (req, res) => {
try {
const flow = fs.readFileSync(`src/store/builder/${req.params.id}-flow.json`)
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({data: flow}))
} catch (err) {
res.writeHead(404, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({errors: "Flow not found"}))
}
})
// To persist new flow via "new flow page"
// In the success case, just echo the flow back
app.post('/backend/flows', bodyParser.json(), (req, res) => {
const container = req.body?.data
res.writeHead(200, { 'Content-Type': 'application/json' })
console.debug('Simulating flow creation ...', container)
res.write(JSON.stringify({data: container}))
res.end()
})
// To persist flow import via "import flow page"
// In the success case, just echo the flow back: the response might have multiple data, but we fetch from createdContainer
app.post('/backend/flows/import', bodyParser.json(), (req, res) => {
const container = req.body?.data
console.debug('Simulating flow import ...', container)
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify({message: 'anything', data: container}))
// For dev: to simulate a failure, just uncomment the follow 02 lines, and comment the 02 previous lines for status 200
// and re-serve the app. Then test an import.
// res.writeHead(500, { 'Content-Type': 'application/json' })
// res.end(JSON.stringify({error: 'simulating 500 error for flow import'}))
})
/**
* To update existing flow
* In the success case, just echo the flow back, but the backend could send back a validation result to display. It's available in:
* vendor_metadata: {
* floip: {
* ui_metadata: {
* validation_results: {
* blocks: {block-uuid1: [{message: 'issue 1'}, {message: 'issue 2'}], ...},
* resources: {resource-uuid1: [
* {dataPath: '/path/1', message: 'issue-1'},
* {dataPath: '/path/2', message: 'issue-2'}],
* ...
* }
* }
* }
* }
* }
*/
app.put('/backend/flows', bodyParser.json(), (req, res) => {
const container = req.body?.data
res.writeHead(200, { 'Content-Type': 'application/json' })
console.debug('Simulating flow update ...', container)
if (container.flows?.length && container.flows[0].blocks?.length > 0) {
console.debug('Simulating validation errors from backend on 1st flow\'s 1st block')
let blockWithValidationIssue = container.flows[0].blocks[0]
// Not all block type have resources, eg: Core.Case
let resourceWithValidationIssue = container.flows[0]?.resources
container.flows[0].vendor_metadata = {
floip: {
ui_metadata: {
validation_results: {
blocks: {
[`${blockWithValidationIssue.uuid}`]: [
{
dataPath: '/dummy/path/non-existing-field',
message: 'dummy-block-backend-validation-error-non-existing-field'
},
// providing a dummy backend validation on block name will help us to simulate duplicate validations,
// so we can handle the scenario appropriately
{
dataPath: '/name',
message: 'dummy-block-backend-validation-error-block-name'
},
]
},
resources: resourceWithValidationIssue.length ? {
[`${resourceWithValidationIssue[0].uuid}`]: [
{
dataPath: '/dummy/path/my-resource/non-existing-field',
message: 'dummy-block-backend-validation-error-resource-non-existing-field'
},
// providing a dummy backend validation on 1st resource will help us to simulate duplicate validations,
// so we can handle the scenario appropriately
{
dataPath: '/values/0/value',
message: 'dummy-block-backend-validation-error-resource-first-field'
},
]
}: []
}
}
}
}
} else {
console.debug('No block found to simulate backend validation, on this container:', container)
}
res.write(JSON.stringify({data: container}))
res.end()
})
//In the success case, just echo the language back
app.post('/backend/languages', bodyParser.json(), (req, res) => {
const language = req.body
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify(language))
})
// Mock call to record start, with this format
// {uuid: ..., queue_id: ..., status: "in_progress", status_description: ..., description: ...}
app.all('/calltorecord/start', (req, res) => {
const result = {
uuid: `${Math.random().toString(36).substr(2, 16)}.${Math.random().toString(36).substr(2, 10)}`,
queue_id: Math.floor(Math.random() * (1000 + 1)),
status: 'in_progress',
status_description: '',
description: 'Test call-to-record audio',
recorder_id: `${req.body.recorder_name.replace(/[\W_]+/g, '')}-${req.body.recorder_phonenumber}`,
}
res.cookie(result.uuid, 'in_progress')
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify(result))
})
// Mock call to record status, with this format
// { audio_file_id: "148", status: "new", description: "my descr", status_description: "", uuid: "5ffcdb4d0d8742.58454366", duration_seconds: "4.54", created_at: "2021-01-11 23:12:50", key: "block_1586301986853_15:45", queueId: "5ffcdb4d0d8742.58454366" }
app.all('/calltorecord/status', (req, res) => {
const now = new Date().toISOString().split('T')
const result = {
audio_file_id: Math.floor(Math.random() * (1000 + 1)),
duration_seconds: Math.random() * 10,
status: req.cookies[req.body.uuid],
description: 'Test call-to-record audio',
uuid: req.body.uuid,
key: req.body.key,
queueId: req.body.queueId,
created_at: `${now[0]} ${now[1].split('.')[0]}`,
}
if (req.cookies[req.body.uuid] !== 'new') {
// `new` status tells the UI we had successful `recorded` audio
res.cookie(result.uuid, 'new')
}
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(JSON.stringify(result))
})
},
},
}