mockaton 8.26.0 → 8.27.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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "8.26.0",
5
+ "version": "8.27.0",
6
6
  "main": "index.js",
7
7
  "types": "index.d.ts",
8
8
  "license": "MIT",
@@ -18,10 +18,10 @@
18
18
  "mockaton": "src/cli.js"
19
19
  },
20
20
  "scripts": {
21
- "test": "node --test \"src/**/*.test.js\"",
22
- "coverage": "node --test --test-reporter=lcov --test-reporter-destination=.coverage/lcov.info --experimental-test-coverage \"src/**/*.test.js\"",
21
+ "test": "node --test 'src/**/*.test.js'",
22
+ "coverage": "node --test --test-reporter=lcov --test-reporter-destination=.coverage/lcov.info --experimental-test-coverage 'src/**/*.test.js'",
23
23
  "start": "node --watch src/cli.js",
24
- "pixaton": "node --test --import=./pixaton-tests/_setup.js --experimental-test-isolation=none \"pixaton-tests/**/*.test.js\"",
24
+ "pixaton": "node --test --import=./pixaton-tests/_setup.js --experimental-test-isolation=none 'pixaton-tests/**/*.test.js'",
25
25
  "outdated": "npm outdated --parseable | awk -F: '{ printf \"npm i %-30s ;# %s\\n\", $4, $2 }'"
26
26
  },
27
27
  "devDependencies": {
package/src/Dashboard.css CHANGED
@@ -87,8 +87,8 @@ body {
87
87
  box-sizing: border-box;
88
88
  padding: 0;
89
89
  border: 0;
90
- font-family: inherit;
91
90
  margin: 0;
91
+ font-family: inherit;
92
92
  font-size: 100%;
93
93
  outline: 0;
94
94
  scrollbar-width: thin;
@@ -150,19 +150,20 @@ header {
150
150
  align-items: flex-end;
151
151
  gap: 16px 10px;
152
152
 
153
- @media (max-width: 879px) {
153
+ @media (max-width: 800px) {
154
154
  max-width: 400px;
155
155
  }
156
156
  }
157
157
 
158
158
  img {
159
- width: 130px;
160
- align-self: center;
159
+ width: 120px;
160
+ align-self: end;
161
161
  margin-right: 22px;
162
+ margin-bottom: 5px;
162
163
  }
163
164
 
164
165
  .Field {
165
- width: 132px;
166
+ width: 116px;
166
167
 
167
168
  span {
168
169
  display: flex;
@@ -219,7 +220,7 @@ header {
219
220
 
220
221
  &.FallbackBackend {
221
222
  position: relative;
222
- width: 210px;
223
+ width: 160px;
223
224
 
224
225
  .SaveProxiedCheckbox {
225
226
  position: absolute;
@@ -258,19 +259,35 @@ header {
258
259
  }
259
260
  }
260
261
 
261
- .Help {
262
+ .MenuTrigger {
262
263
  min-width: 24px;
263
264
  align-self: end;
264
265
  margin-left: auto;
265
266
  fill: var(--colorSecondaryAction);
267
+ background: transparent;
266
268
 
267
269
  &:hover {
268
270
  fill: var(--colorAccent);
269
271
  }
272
+ }
273
+ }
270
274
 
271
- @media (max-width: 520px) {
272
- display: none;
273
- }
275
+ #Menu {
276
+ position: absolute;
277
+ top: 62px;
278
+ right: 10px;
279
+ left: auto;
280
+ padding: 20px;
281
+ border: 1px solid var(--colorSecondaryActionBorder);
282
+ border-radius: var(--radius);
283
+ box-shadow: var(--boxShadow1);
284
+ background: var(--colorHeaderBackground);
285
+
286
+ .GroupByMethod {
287
+ display: flex;
288
+ align-items: center;
289
+ margin-bottom: 12px;
290
+ gap: 4px;
274
291
  }
275
292
  }
276
293
 
@@ -280,11 +297,7 @@ main {
280
297
  min-height: 0;
281
298
  grid-template-columns: minmax(min-content, max-content) 1fr;
282
299
 
283
- @media (max-width: 1160px) {
284
- grid-template-columns: min(580px) 1fr;
285
- }
286
-
287
- @media (max-width: 879px) {
300
+ @media (max-width: 800px) {
288
301
  grid-template-columns: 100%;
289
302
  grid-template-rows: 1fr 1fr;
290
303
  }
package/src/Dashboard.js CHANGED
@@ -12,11 +12,12 @@ const Strings = {
12
12
  delay: 'Delay',
13
13
  delay_ms: 'Delay (ms)',
14
14
  empty_response_body: '/* Empty Response Body */',
15
- fallback_server: 'Fallback Backend',
15
+ fallback_server: 'Fallback',
16
16
  fallback_server_error: '⛔ Fallback Backend Error',
17
- fallback_server_placeholder: 'Type Server Address',
17
+ fallback_server_placeholder: 'Type Backend Address',
18
18
  fetching: 'Fetching…',
19
19
  got: 'Got',
20
+ group_by_method: 'Group by Method',
20
21
  internal_server_error: 'Internal Server Error',
21
22
  no_mocks_found: 'No mocks found',
22
23
  not_found: 'Not Found',
@@ -37,8 +38,9 @@ const CSS = {
37
38
  FallbackBackend: null,
38
39
  Field: null,
39
40
  GlobalDelayField: null,
40
- Help: null,
41
+ GroupByMethod: null,
41
42
  InternalServerErrorToggler: null,
43
+ MenuTrigger: null,
42
44
  MockList: null,
43
45
  MockSelector: null,
44
46
  NotFoundToggler: null,
@@ -92,6 +94,8 @@ const state = {
92
94
 
93
95
  fallbackAddress: '',
94
96
 
97
+ groupByMethod: true, // TODO read from localstorage
98
+
95
99
  get canProxy() {
96
100
  return Boolean(this.fallbackAddress)
97
101
  }
@@ -129,6 +133,7 @@ const s = createSvgElement
129
133
  function App() {
130
134
  return [
131
135
  r(Header),
136
+ r(Menu),
132
137
  r('main', null,
133
138
  r('div', className(CSS.leftSide),
134
139
  r(MockList),
@@ -148,17 +153,42 @@ function Header() {
148
153
  width: 160
149
154
  }),
150
155
  r('div', null,
156
+ r(GlobalDelayField),
151
157
  r(CookieSelector),
152
158
  r(BulkSelector),
153
- r(GlobalDelayField),
154
159
  r(ProxyFallbackField),
155
160
  r(ResetButton)),
161
+ r('button', {
162
+ className: CSS.MenuTrigger,
163
+ popovertarget: 'Menu'
164
+ }, r(MenuIcon))
165
+ ))
166
+ }
167
+
168
+ function Menu() {
169
+ return (
170
+ r('menu', {
171
+ id: 'Menu',
172
+ popover: ''
173
+ },
174
+ r('label', className(CSS.GroupByMethod),
175
+ r('input', {
176
+ type: 'checkbox',
177
+ checked: state.groupByMethod,
178
+ onChange() {
179
+ state.groupByMethod = !state.groupByMethod
180
+ updateState()
181
+ // TODO localstorage
182
+ }
183
+ }),
184
+ r('span', null, Strings.group_by_method)),
185
+
156
186
  r('a', {
157
- className: CSS.Help,
158
187
  href: 'https://github.com/ericfortis/mockaton',
159
188
  target: '_blank',
160
189
  rel: 'noopener noreferrer'
161
- }, r(HelpIcon))))
190
+ }, 'Documentation')
191
+ ))
162
192
  }
163
193
 
164
194
 
@@ -306,38 +336,69 @@ function ResetButton() {
306
336
  /** # MockList */
307
337
 
308
338
  function MockList() {
309
- const { brokersByMethod } = state
339
+ const { brokersByMethod, groupByMethod } = state
310
340
  if (!Object.keys(brokersByMethod).length)
311
341
  return (
312
342
  r('div', className(CSS.empty),
313
343
  Strings.no_mocks_found))
344
+
345
+ if (groupByMethod)
346
+ return (
347
+ r('div', null,
348
+ r('table', null, Object.entries(brokersByMethod).map(([method, brokers]) =>
349
+ r(RowsByMethod, { method, brokers })))))
350
+
314
351
  return (
315
352
  r('div', null,
316
- r('table', null, Object.entries(brokersByMethod).map(([method, brokers]) =>
317
- r(SectionByMethod, { method, brokers })))))
353
+ r('table', null,
354
+ r(RowsUngrouped))))
318
355
  }
319
356
 
320
- function SectionByMethod({ method, brokers }) {
357
+ function RowsByMethod({ method, brokers }) {
321
358
  const canProxy = state.canProxy
322
- const brokersSorted = Object.entries(brokers)
323
- .filter(([, broker]) => broker.mocks.length > 1) // >1 because of autogen500
324
- .sort((a, b) => a[0].localeCompare(b[0]))
325
-
326
- const urlMasks = brokersSorted.map(([urlMask]) => urlMask)
327
- const urlMasksDittoed = dittoSplitPaths(urlMasks)
359
+ const rawRows = Object.entries(brokers).map(([urlMask, broker]) => [urlMask, broker, method])
328
360
  return (
329
361
  r('tbody', null,
330
362
  r('tr', null,
331
363
  r('th', { colspan: 2 + Number(canProxy) }),
332
364
  r('th', null, method)),
333
- brokersSorted.map(([urlMask, broker], i) =>
334
- r('tr', { 'data-method': method, 'data-urlMask': urlMask },
335
- canProxy && r('td', null, r(ProxyToggler, { broker })),
336
- r('td', null, r(DelayRouteToggler, { broker })),
337
- r('td', null, r(InternalServerErrorToggler, { broker })),
338
- r('td', null, r(PreviewLink, { method, urlMask, urlMaskDittoed: urlMasksDittoed[i] })),
339
- r('td', null, r(MockSelector, { broker }))
340
- ))))
365
+ Rows(rawRows)))
366
+ }
367
+
368
+ function RowsUngrouped() {
369
+ const { brokersByMethod } = state
370
+ const rawRows = []
371
+ for (const [method, brokers] of Object.entries(brokersByMethod))
372
+ for (const [urlMask, broker] of Object.entries(brokers))
373
+ rawRows.push([urlMask, broker, method])
374
+
375
+ return r('tbody', null, Rows(rawRows))
376
+ }
377
+
378
+ function Rows(rawRows) {
379
+ const sorted = rawRows
380
+ .filter(([, broker]) => broker.mocks.length > 1) // >1 because of autogen500
381
+ .sort(([aUrl], [bUrl]) => aUrl.localeCompare(bUrl))
382
+ const urlMasksDittoed = dittoSplitPaths(sorted.map(([urlMask]) => urlMask))
383
+ return sorted.map(([urlMask, broker, method], i) =>
384
+ r(Row, {
385
+ broker,
386
+ method,
387
+ urlMask,
388
+ urlMaskDittoed: urlMasksDittoed[i]
389
+ }))
390
+ }
391
+
392
+ function Row({ method, urlMask, urlMaskDittoed, broker }) {
393
+ const canProxy = state.canProxy
394
+ return (
395
+ r('tr', { 'data-method': method, 'data-urlMask': urlMask },
396
+ canProxy && r('td', null, r(ProxyToggler, { broker })),
397
+ r('td', null, r(DelayRouteToggler, { broker })),
398
+ r('td', null, r(InternalServerErrorToggler, { broker })),
399
+ r('td', null, r(PreviewLink, { method, urlMask, urlMaskDittoed })),
400
+ r('td', null, r(MockSelector, { broker }))
401
+ ))
341
402
  }
342
403
 
343
404
  function PreviewLink({ method, urlMask, urlMaskDittoed }) {
@@ -365,6 +426,8 @@ function PreviewLink({ method, urlMask, urlMaskDittoed }) {
365
426
 
366
427
  /** @param {{ broker: ClientMockBroker }} props */
367
428
  function MockSelector({ broker }) {
429
+ const { groupByMethod } = state
430
+
368
431
  function onChange() {
369
432
  const { urlMask, method } = parseFilename(this.value)
370
433
  mockaton.select(this.value)
@@ -384,6 +447,15 @@ function MockSelector({ broker }) {
384
447
  files.push(selected)
385
448
  }
386
449
 
450
+ function nameFor(file) {
451
+ if (file === Strings.proxied)
452
+ return Strings.proxied
453
+ const { status, ext, method } = parseFilename(file)
454
+ return groupByMethod
455
+ ? `${status} ${ext} ${extractComments(file).join(' ')}`
456
+ : `${method} ${status} ${ext} ${extractComments(file).join(' ')}`
457
+ }
458
+
387
459
  return (
388
460
  r('select', {
389
461
  onChange,
@@ -394,15 +466,11 @@ function MockSelector({ broker }) {
394
466
  CSS.MockSelector,
395
467
  selected !== files[0] && CSS.nonDefault,
396
468
  status >= 400 && status < 500 && CSS.status4xx)
397
- }, files.map(file => {
398
- const { status, ext } = parseFilename(file)
399
- return (
400
- r('option', {
401
- value: file,
402
- selected: file === selected
403
- }, `${status} ${ext} ${extractComments(file).join(' ')}`)
404
- )
405
- })))
469
+ }, files.map(file => (
470
+ r('option', {
471
+ value: file,
472
+ selected: file === selected
473
+ }, nameFor(file))))))
406
474
  }
407
475
 
408
476
  /** @param {{ broker: ClientMockBroker }} props */
@@ -710,10 +778,10 @@ function CloudIcon() {
710
778
  s('path', { d: 'm6.1 9.1c2.8 0 5 2.3 5 5' })))
711
779
  }
712
780
 
713
- function HelpIcon() {
781
+ function MenuIcon() {
714
782
  return (
715
783
  s('svg', { viewBox: '0 0 24 24' },
716
- s('path', { d: 'M11 18h2v-2h-2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8m0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4' })))
784
+ s('path', { d: 'M3 18h18v-2H3zm0-5h18v-2H3zm0-7v2h18V6z' })))
717
785
  }
718
786
 
719
787
  /**
@@ -878,7 +946,7 @@ function syntaxJSON(json) {
878
946
  while ((match = syntaxJSON.regex.exec(json)) !== null) {
879
947
  if (nNodes > MAX_NODES)
880
948
  break
881
-
949
+
882
950
  if (match.index > lastIndex)
883
951
  text(json.slice(lastIndex, match.index))
884
952
 
@@ -926,7 +994,7 @@ function syntaxXML(xml) {
926
994
  while ((match = syntaxXML.regex.exec(xml)) !== null) {
927
995
  if (nNodes > MAX_NODES)
928
996
  break
929
-
997
+
930
998
  if (match.index > lastIndex)
931
999
  text(xml.slice(lastIndex, match.index))
932
1000