mockaton 12.0.1 → 12.1.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/README.md CHANGED
@@ -27,9 +27,9 @@ For example, for [/api/company/123](#), the filename could be:
27
27
  ## Dashboard
28
28
 
29
29
  <picture>
30
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.light.gold.png">
31
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.dark.gold.png">
32
- <img alt="Mockaton Dashboard" src="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp832x740.dark.gold.png">
30
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp762x762.light.gold.png">
31
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp762x762.dark.gold.png">
32
+ <img alt="Mockaton Dashboard" src="https://raw.githubusercontent.com/ericfortis/mockaton/refs/heads/main/pixaton-tests/tests/macos/pic-for-readme.vp762x762.dark.gold.png">
33
33
  </picture>
34
34
 
35
35
  On the dashboard you can:
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "mockaton",
3
3
  "description": "HTTP Mock Server",
4
4
  "type": "module",
5
- "version": "12.0.1",
5
+ "version": "12.1.1",
6
6
  "exports": {
7
7
  ".": {
8
8
  "import": "./index.js",
package/src/client/app.js CHANGED
@@ -1,8 +1,4 @@
1
- import {
2
- createElement as r,
3
- createSvgElement as s,
4
- className, restoreFocus, Defer, Fragment, adoptCSS
5
- } from './dom-utils.js'
1
+ import { createElement as r, createSvgElement as s, className, restoreFocus, Defer, Fragment, adoptCSS } from './dom-utils.js'
6
2
 
7
3
  import { store } from './app-store.js'
8
4
  import { parseFilename } from './Filename.js'
@@ -47,6 +43,9 @@ function App() {
47
43
  style: { width: leftSideRef.width },
48
44
  className: CSS.leftSide
49
45
  },
46
+ r('div', className(CSS.SubToolbar),
47
+ GroupByMethod(),
48
+ BulkSelector()),
50
49
  r('div', className(CSS.Table),
51
50
  MockList(),
52
51
  StaticFilesList())),
@@ -68,7 +67,6 @@ function Header() {
68
67
  r('div', className(CSS.GlobalDelayWrap),
69
68
  GlobalDelayField(),
70
69
  GlobalDelayJitterField()),
71
- BulkSelector(),
72
70
  CookieSelector(),
73
71
  ProxyFallbackField(),
74
72
  ResetButton(),
@@ -136,30 +134,6 @@ function GlobalDelayJitterField() {
136
134
  }
137
135
 
138
136
 
139
- function BulkSelector() {
140
- const { comments } = store
141
- const firstOption = t`Pick Comment…`
142
- function onChange() {
143
- const value = this.value
144
- this.value = firstOption // hack so it’s always selected
145
- store.bulkSelectByComment(value)
146
- }
147
- const disabled = !comments.length
148
- return (
149
- r('label', className(CSS.Field),
150
- r('span', null, t`Bulk Select`),
151
- r('select', {
152
- className: CSS.BulkSelector,
153
- autocomplete: 'off',
154
- disabled,
155
- title: disabled ? t`No mock files have comments which are anything within parentheses on the filename.` : '',
156
- onChange
157
- },
158
- r('option', { value: firstOption }, firstOption),
159
- r('hr'),
160
- comments.map(value => r('option', { value }, value)))))
161
- // TODO For a11y, use `menu` instead of `select`
162
- }
163
137
 
164
138
  function CookieSelector() {
165
139
  const { cookies } = store
@@ -234,39 +208,24 @@ function SettingsMenuTrigger() {
234
208
  popovertarget: id,
235
209
  className: CSS.MenuTrigger
236
210
  },
237
- SettingsIcon(),
211
+ InfoIcon(),
238
212
  Defer(() => SettingsMenu(id))))
239
213
  }
240
214
 
241
215
  function SettingsMenu(id) {
242
- const firstInputRef = {}
243
216
  return (
244
217
  r('menu', {
245
218
  id,
246
219
  popover: '',
247
- className: CSS.SettingsMenu,
248
- onToggle(event) {
249
- if (event.newState === 'open')
250
- firstInputRef.elem.focus()
251
- }
220
+ className: CSS.SettingsMenu
252
221
  },
253
222
 
254
223
  r('div', null,
255
- r('label', className(CSS.GroupByMethod),
256
- r('input', {
257
- name: 'group-by-method',
258
- ref: firstInputRef,
259
- type: 'checkbox',
260
- checked: store.groupByMethod,
261
- onChange: store.toggleGroupByMethod
262
- }),
263
- r('span', className(CSS.checkboxBody), t`Group by Method`)),
264
-
265
224
  r('a', {
266
225
  href: 'https://mockaton.com',
267
226
  target: '_blank',
268
227
  rel: 'noopener noreferrer'
269
- }, t`Website`),
228
+ }, t`Documentation`),
270
229
 
271
230
  r('a', {
272
231
  href: 'https://github.com/ericfortis/mockaton',
@@ -280,6 +239,47 @@ function SettingsMenu(id) {
280
239
 
281
240
 
282
241
 
242
+ /** # Left Side */
243
+
244
+
245
+ function BulkSelector() {
246
+ const { comments } = store
247
+ const firstOption = t`Pick Comment…`
248
+ function onChange() {
249
+ const value = this.value
250
+ this.value = firstOption // hack so it’s always selected
251
+ store.bulkSelectByComment(value)
252
+ }
253
+ const disabled = !comments.length
254
+ return (
255
+ r('label', className(CSS.BulkSelector),
256
+ r('span', null, t`Bulk Select`),
257
+ r('select', {
258
+ autocomplete: 'off',
259
+ disabled,
260
+ title: disabled ? t`No mock files have comments which are anything within parentheses on the filename.` : '',
261
+ onChange
262
+ },
263
+ r('option', { value: firstOption }, firstOption),
264
+ r('hr'),
265
+ comments.map(value => r('option', { value }, value)))))
266
+ // TODO For a11y, use `menu` instead of `select`
267
+ }
268
+
269
+
270
+ function GroupByMethod() {
271
+ return (
272
+ r('label', className(CSS.GroupByMethod),
273
+ r('input', {
274
+ name: 'group-by-method',
275
+ type: 'checkbox',
276
+ checked: store.groupByMethod,
277
+ onChange: store.toggleGroupByMethod
278
+ }),
279
+ r('span', className(CSS.checkboxBody), t`Group by Method`)))
280
+ }
281
+
282
+
283
283
  /** # MockList */
284
284
 
285
285
  function MockList() {
@@ -540,7 +540,7 @@ function Resizer(ref) {
540
540
  }
541
541
 
542
542
  function onMove(event) {
543
- const MIN_LEFT_WIDTH = 340
543
+ const MIN_LEFT_WIDTH = 350
544
544
  raf = raf || requestAnimationFrame(() => {
545
545
  ref.width = Math.max(initialWidth - (initialX - event.clientX), MIN_LEFT_WIDTH) + 'px'
546
546
  ref.elem.style.width = ref.width
@@ -575,13 +575,19 @@ const payloadViewerCodeRef = {}
575
575
  function PayloadViewer() {
576
576
  return (
577
577
  r('div', className(CSS.PayloadViewer),
578
- r('h2', { ref: payloadViewerTitleRef },
579
- !store.hasChosenLink && t`Preview`),
578
+ RightToolbar(),
580
579
  r('pre', null,
581
580
  r('code', { ref: payloadViewerCodeRef },
582
581
  !store.hasChosenLink && t`Click a link to preview it`))))
583
582
  }
584
583
 
584
+ function RightToolbar() {
585
+ return r('div', className(CSS.SubToolbar),
586
+ r('h2', { ref: payloadViewerTitleRef },
587
+ !store.hasChosenLink && t`Preview`))
588
+ }
589
+
590
+
585
591
  function PayloadViewerTitle(file, statusText) {
586
592
  const { method, status, ext } = parseFilename(file)
587
593
  const fileNameWithComments = file.split('.').slice(0, -3).join('.')
@@ -731,10 +737,10 @@ function CloudIcon() {
731
737
  s('path', { d: 'm6.1 9.1c2.8 0 5 2.3 5 5' })))
732
738
  }
733
739
 
734
- function SettingsIcon() {
740
+ function InfoIcon() {
735
741
  return (
736
742
  s('svg', { viewBox: '0 0 24 24' },
737
- s('path', { d: 'M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6' })))
743
+ s('path', { d: 'M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m1 15h-2v-6h2zm0-8h-2V7h2z' })))
738
744
  }
739
745
 
740
746
 
@@ -11,9 +11,9 @@
11
11
  --colorBackground: #fff;
12
12
  --colorComboBoxHeaderBackground: #fff;
13
13
  --colorComboBoxBackground: #eee;
14
- --colorHeaderBackground: #efefef;
14
+ --colorHeaderBackground: #f5f5f5;
15
15
  --colorSecondaryButtonBackground: #fcfcfc;
16
- --colorSecondaryActionBorder: #ddd;
16
+ --colorSecondaryActionBorder: #e0e0e0;
17
17
  --colorSecondaryAction: #666;
18
18
  --colorDisabledMockSelector: #444;
19
19
  --colorHover: rgba(119, 193, 255, 0.5);
@@ -102,10 +102,6 @@ a {
102
102
  color: var(--colorAccent);
103
103
  }
104
104
 
105
- input[type="number"]:not(:focus) {
106
- -moz-appearance: textfield;
107
- }
108
-
109
105
  select {
110
106
  border: 1px solid transparent;
111
107
  font-size: 100%;
@@ -126,7 +122,7 @@ select {
126
122
  }
127
123
  &:disabled {
128
124
  cursor: not-allowed;
129
- opacity: 0.5;
125
+ opacity: 50%;
130
126
  }
131
127
  }
132
128
 
@@ -141,16 +137,22 @@ header {
141
137
  align-self: end;
142
138
  margin-right: 22px;
143
139
  margin-bottom: 3px;
140
+ opacity: 85%;
141
+ transition: opacity 240ms ease-in-out;
142
+
143
+ &:hover {
144
+ opacity: 1;
145
+ }
146
+
147
+ @media (max-width: 730px) {
148
+ display: none;
149
+ }
144
150
 
145
151
  svg {
146
152
  width: 120px;
147
153
  pointer-events: none;
148
154
  fill: var(--colorText);
149
155
  }
150
-
151
- @media (max-width: 830px) {
152
- display: none;
153
- }
154
156
  }
155
157
 
156
158
  > div {
@@ -158,9 +160,9 @@ header {
158
160
  width: 100%;
159
161
  flex-wrap: wrap;
160
162
  align-items: flex-end;
161
- gap: 16px 8px;
163
+ gap: 16px 12px;
162
164
 
163
- @media (max-width: 690px) {
165
+ @media (max-width: 590px) {
164
166
  .MenuTrigger {
165
167
  margin-left: unset;
166
168
  }
@@ -171,111 +173,6 @@ header {
171
173
  display: flex;
172
174
  }
173
175
 
174
- .Field {
175
- width: 116px;
176
-
177
- span {
178
- display: flex;
179
- align-items: center;
180
- margin-left: 8px;
181
- color: var(--colorLabel);
182
- font-size: 11px;
183
- gap: 4px;
184
- }
185
-
186
- input[type=url],
187
- input[type=number],
188
- select {
189
- width: 100%;
190
- height: 28px;
191
- padding: 4px 8px;
192
- border: 1px solid var(--colorSecondaryActionBorder);
193
- margin-top: 2px;
194
- color: var(--colorText);
195
- font-size: 11px;
196
- background-color: var(--colorComboBoxHeaderBackground);
197
- border-radius: var(--radius);
198
- }
199
-
200
- &.GlobalDelayField {
201
- position: relative;
202
- width: 76px;
203
-
204
- input {
205
- padding-right: 6px;
206
- border-bottom-right-radius: 0;
207
- border-top-right-radius: 0;
208
- }
209
-
210
- svg {
211
- width: 12px;
212
- height: 12px;
213
- border: 1px solid var(--colorLabel);
214
- stroke-width: 3px;
215
- border-radius: 50%;
216
- }
217
-
218
- &:focus-within {
219
- z-index: 100;
220
- }
221
- }
222
-
223
- &.GlobalDelayJitterField {
224
- width: 80px;
225
- span {
226
- margin-left: 4px;
227
- }
228
- input {
229
- border-left: 2px solid transparent;
230
- border-bottom-left-radius: 0;
231
- border-top-left-radius: 0;
232
- }
233
- &:focus-within {
234
- z-index: 100;
235
- }
236
- }
237
-
238
- &.CookieSelector {
239
- width: 100px;
240
- }
241
-
242
- &.FallbackBackend {
243
- position: relative;
244
- width: 150px;
245
-
246
- .SaveProxiedCheckbox {
247
- position: absolute;
248
- top: 0;
249
- right: 0;
250
- display: flex;
251
- width: auto;
252
- min-width: unset;
253
- align-items: center;
254
- font-size: 11px;
255
- gap: 4px;
256
-
257
- input + .checkboxBody {
258
- margin: 0;
259
- margin-right: 4px;
260
- }
261
- input:enabled + .checkboxBody {
262
- cursor: pointer;
263
- }
264
- input:disabled {
265
- cursor: not-allowed;
266
- }
267
- input:disabled + .checkboxBody {
268
- opacity: 0.8;
269
- cursor: not-allowed;
270
- }
271
- }
272
- }
273
- }
274
-
275
- .BulkSelector {
276
- background-image: none;
277
- text-align-last: center;
278
- }
279
176
 
280
177
  .ResetButton {
281
178
  padding: 6px 12px;
@@ -312,6 +209,107 @@ header {
312
209
  }
313
210
  }
314
211
 
212
+ .Field {
213
+ width: 116px;
214
+
215
+ span {
216
+ display: flex;
217
+ align-items: center;
218
+ margin-left: 8px;
219
+ color: var(--colorLabel);
220
+ font-size: 11px;
221
+ gap: 4px;
222
+ }
223
+
224
+ input[type=url],
225
+ input[type=number],
226
+ select {
227
+ width: 100%;
228
+ height: 28px;
229
+ padding: 4px 8px;
230
+ border: 1px solid var(--colorSecondaryActionBorder);
231
+ margin-top: 2px;
232
+ color: var(--colorText);
233
+ font-size: 11px;
234
+ background-color: var(--colorComboBoxHeaderBackground);
235
+ border-radius: var(--radius);
236
+ }
237
+
238
+ &.GlobalDelayField {
239
+ position: relative;
240
+ width: 76px;
241
+
242
+ input {
243
+ padding-right: 6px;
244
+ border-bottom-right-radius: 0;
245
+ border-top-right-radius: 0;
246
+ }
247
+
248
+ svg {
249
+ width: 12px;
250
+ height: 12px;
251
+ border: 1px solid var(--colorLabel);
252
+ stroke-width: 3px;
253
+ border-radius: 50%;
254
+ }
255
+
256
+ &:focus-within {
257
+ z-index: 100;
258
+ }
259
+ }
260
+
261
+ &.GlobalDelayJitterField {
262
+ width: 80px;
263
+ span {
264
+ margin-left: 4px;
265
+ }
266
+ input {
267
+ border-left: 2px solid transparent;
268
+ border-bottom-left-radius: 0;
269
+ border-top-left-radius: 0;
270
+ }
271
+ &:focus-within {
272
+ z-index: 100;
273
+ }
274
+ }
275
+
276
+ &.CookieSelector {
277
+ width: 100px;
278
+ }
279
+
280
+ &.FallbackBackend {
281
+ position: relative;
282
+ width: 150px;
283
+
284
+ .SaveProxiedCheckbox {
285
+ position: absolute;
286
+ top: 0;
287
+ right: 0;
288
+ display: flex;
289
+ width: auto;
290
+ min-width: unset;
291
+ align-items: center;
292
+ font-size: 11px;
293
+ gap: 4px;
294
+
295
+ input + .checkboxBody {
296
+ margin: 0;
297
+ margin-right: 4px;
298
+ }
299
+ input:enabled + .checkboxBody {
300
+ cursor: pointer;
301
+ }
302
+ input:disabled {
303
+ cursor: not-allowed;
304
+ }
305
+ input:disabled + .checkboxBody {
306
+ opacity: 0.8;
307
+ cursor: not-allowed;
308
+ }
309
+ }
310
+ }
311
+ }
312
+
315
313
  .SettingsMenu {
316
314
  position: absolute;
317
315
  top: 62px;
@@ -331,16 +329,9 @@ header {
331
329
  gap: 12px;
332
330
  text-align: left;
333
331
 
334
- .GroupByMethod {
335
- display: flex;
336
- align-items: center;
337
- gap: 6px;
338
- cursor: pointer;
339
- }
340
332
  }
341
333
  }
342
334
 
343
-
344
335
  main {
345
336
  display: flex;
346
337
  min-width: 0;
@@ -362,10 +353,7 @@ main {
362
353
 
363
354
  .leftSide {
364
355
  width: 50%; /* resizable in js */
365
- padding: 16px;
366
356
  border-right: 1px solid var(--colorSecondaryActionBorder);
367
- user-select: none;
368
- overflow-y: auto;
369
357
  box-shadow: var(--boxShadow1);
370
358
  }
371
359
 
@@ -391,10 +379,49 @@ main {
391
379
  }
392
380
  }
393
381
 
382
+ .SubToolbar {
383
+ display: flex;
384
+ height: 42px;
385
+ align-items: center;
386
+ justify-content: space-between;
387
+ padding-right: 14px;
388
+ padding-left: 16px;
389
+ border-bottom: 1px solid var(--colorSecondaryActionBorder);
390
+ background: var(--colorHeaderBackground);
391
+ }
392
+
393
+ .GroupByMethod {
394
+ display: flex;
395
+ align-items: center;
396
+ gap: 6px;
397
+ cursor: pointer;
398
+ }
399
+
400
+ .BulkSelector {
401
+ select {
402
+ width: 110px;
403
+ padding: 6px 8px;
404
+ border: 1px solid var(--colorSecondaryActionBorder);
405
+ margin-left: 4px;
406
+ background-image: none;
407
+ text-align-last: center;
408
+ color: var(--colorText);
409
+ font-size: 11px;
410
+ background-color: var(--colorComboBoxHeaderBackground);
411
+ border-radius: var(--radius);
412
+ }
413
+ }
414
+
394
415
  .Table {
416
+ height: 100%;
417
+ padding: 16px;
418
+ padding-left: 12px;
419
+ user-select: none;
420
+ overflow-y: auto;
421
+
395
422
  .TableHeading {
396
423
  padding-bottom: 4px;
397
- padding-left: 4px;
424
+ padding-left: 1px;
398
425
  border-top: 24px solid transparent;
399
426
  margin-left: 74px;
400
427
  font-weight: bold;
@@ -647,12 +674,6 @@ main {
647
674
 
648
675
  .PayloadViewer {
649
676
  height: 100%;
650
- padding-top: 16px;
651
-
652
- > h2 {
653
- padding-bottom: 4px;
654
- padding-left: 16px;
655
- }
656
677
 
657
678
  > pre {
658
679
  overflow: auto;
@@ -688,8 +709,9 @@ main {
688
709
 
689
710
  .ProgressBar {
690
711
  position: relative;
691
- top: -4px;
692
- width: 100%;
712
+ top: -12px;
713
+ left: -16px;
714
+ width: calc(100% + 32px);
693
715
  height: 2px;
694
716
  background: var(--colorComboBoxHeaderBackground);
695
717