systemview 1.20.1 → 1.22.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/cli/runTests.js CHANGED
@@ -1,6 +1,7 @@
1
- const fs = require("fs");
2
- const path = require("path");
3
- const { createCookieClient } = require("./cookieClient");
1
+ const { createClient } = require("systemlynx");
2
+ const { createCookieHttpClient } = require("./cookieClient");
3
+ const cookieHttpClient = createCookieHttpClient();
4
+ const Client = createClient(cookieHttpClient);
4
5
  const { initializeSavedTests } = require("../testing-utilities/transformTests");
5
6
  const FullTestController = require("../testing-utilities/FullTestController");
6
7
  const log = require("./logger");
@@ -45,7 +46,6 @@ module.exports = async function runTests(
45
46
  {
46
47
  json = false,
47
48
  verbose = false,
48
- manifest: manifestPath,
49
49
  headers: cliHeaders = {},
50
50
  bail = false,
51
51
  dryRun = false,
@@ -61,23 +61,25 @@ module.exports = async function runTests(
61
61
  return 1;
62
62
  }
63
63
 
64
- const { services: connectedServices, probeHeaders: manifestHeaders } = await resolveServices(
65
- api,
66
- project_code,
67
- manifestPath
68
- );
64
+ const { services: connectedServices, resolvedNamespace } = await resolveServices(api, project_code);
65
+ if (resolvedNamespace && !namespace) namespace = resolvedNamespace;
69
66
  if (!connectedServices || !connectedServices.length) {
70
67
  log.warn("No connected services found for project: " + project_code);
71
68
  return 1;
72
69
  }
73
70
 
74
- const extraHeaders = { ...manifestHeaders, ...cliHeaders };
75
- const Client = createCookieClient(extraHeaders);
71
+ const extraHeaders = { ...cliHeaders };
76
72
 
77
73
  if (!json) {
78
74
  connectedServices.forEach(({ serviceId, system }) => {
79
75
  log.success(`connected: ${serviceId} @ ${system.connectionData.serviceUrl}`);
80
76
  });
77
+ if (namespace || skipPatterns.length) {
78
+ console.log("");
79
+ console.log(chalk.dim(` Filters:`));
80
+ if (namespace) console.log(` ${chalk.dim(`namespace: ${chalk.white(namespace)}`)}`);
81
+ if (skipPatterns.length) console.log(` ${chalk.dim(`skip: ${chalk.white(skipPatterns.join(", "))}`)}`);
82
+ }
81
83
  }
82
84
 
83
85
  const allTestLists = await getTests(connectedServices, Client);
@@ -121,7 +123,7 @@ module.exports = async function runTests(
121
123
  if (!json) log.info(`Initializing tests for ${serviceId}...`);
122
124
 
123
125
  try {
124
- const initialized = initializeSavedTests(testList, connectedServices, Client);
126
+ const initialized = initializeSavedTests(testList, connectedServices, Client, extraHeaders);
125
127
  const { passed, failed, jsonTests, failures } = await runAllTests(
126
128
  initialized,
127
129
  url,
@@ -354,39 +356,32 @@ async function getTests(connectedServices, Client) {
354
356
  return results;
355
357
  }
356
358
 
357
- async function resolveServices(api, project_code, manifestPath) {
358
- const manifestFile = manifestPath || path.join(process.cwd(), "systemview.manifest.json");
359
+ async function resolveServices(api, project_code) {
360
+ try {
361
+ const { SystemView } = await Client.loadService(api);
359
362
 
360
- if (fs.existsSync(manifestFile)) {
361
- try {
362
- const raw = JSON.parse(fs.readFileSync(manifestFile, "utf8"));
363
- const services = raw.services
364
- ? raw.services
365
- : [{ serviceId: raw.serviceId, system: raw.system, specList: raw.specList }];
366
-
367
- if (project_code && raw.projectCode && raw.projectCode !== project_code) {
368
- log.warn(
369
- `Manifest projectCode "${raw.projectCode}" doesn't match "${project_code}", falling back to API`
370
- );
371
- } else {
372
- return { services, probeHeaders: raw.probeHeaders || {} };
373
- }
374
- } catch (err) {
375
- log.warn(`Failed to read manifest: ${err.message}`);
363
+ // Try exact project code match first
364
+ const services = await SystemView.getServices(project_code);
365
+ if (services && services.length) {
366
+ return { services };
376
367
  }
377
- }
378
368
 
379
- const BaseClient = createCookieClient();
380
- const services = await getConnectedServices(api, project_code, BaseClient);
381
- return { services, probeHeaders: {} };
382
- }
369
+ // Fuzzy namespace: check if project_code matches any module or method across all services
370
+ const projects = await SystemView.getProjects();
371
+ const all = Object.values(projects).flat();
372
+ const isNamespace = all.some(({ system }) =>
373
+ (system.connectionData.modules || []).some(({ name, methods }) =>
374
+ name.toLowerCase().includes(project_code.toLowerCase()) ||
375
+ (methods || []).some(({ fn }) => fn.toLowerCase().includes(project_code.toLowerCase()))
376
+ )
377
+ );
378
+ if (isNamespace) {
379
+ return { services: all, resolvedNamespace: project_code };
380
+ }
383
381
 
384
- async function getConnectedServices(api, project_code, Client) {
385
- try {
386
- const { SystemView } = await Client.loadService(api);
387
- return await SystemView.getServices(project_code);
382
+ return { services: [] };
388
383
  } catch (error) {
389
384
  log.error("Failed to connect to SystemView: " + error.message);
390
- return [];
385
+ return { services: [] };
391
386
  }
392
387
  }
@@ -1,34 +1,179 @@
1
1
  const runTests = require("./runTests");
2
- const cli = require("./utils/cli");
2
+ const listTests = require("./listTests");
3
+ const connectService = require("./connectService");
4
+ const manifestCommands = require("./manifest");
5
+ const probe = require("./probe");
3
6
  const openBrowser = require("./openBrowser");
7
+ const logsCommand = require("./logs");
8
+ const log = require("./logger");
9
+ const cli = require("./utils/cli");
4
10
  const readline = require("readline");
11
+ const { createClient } = require("systemlynx");
12
+ const { createCookieHttpClient } = require("./cookieClient");
13
+ const Client = createClient(createCookieHttpClient());
5
14
 
6
- module.exports = function startLineReader(url) {
15
+ module.exports = async function startLineReader(url, { connectedUrls = new Set() } = {}) {
7
16
  const lineReader = readline.createInterface({
8
17
  input: process.stdin,
9
18
  output: process.stdout,
10
19
  });
11
- const handleInput = (input = "") => {
12
- const args = input.split(" ").map((s) => s.trim());
13
- const command = args.shift();
14
- if (["exit", "q", "shutdown", "stop"].includes(command)) {
20
+
21
+ let CLI = null;
22
+ try {
23
+ ({ CLI } = await Client.loadService(`${url}/systemview/api`));
24
+ const history = await CLI.getHistory();
25
+ lineReader.history = [...history].reverse();
26
+ } catch {}
27
+
28
+ let stopLogs = null;
29
+
30
+ const parseArgs = (args) => {
31
+ const flags = { filter: [], or: [], include: [], skip: [], headers: {} };
32
+ const positional = [];
33
+ for (let i = 0; i < args.length; i++) {
34
+ if (args[i] === "--level" && args[i + 1]) { flags.level = args[++i]; }
35
+ else if (args[i] === "--limit" && args[i + 1]) { flags.limit = parseInt(args[++i], 10); }
36
+ else if (args[i] === "--filter" && args[i + 1]) { flags.filter.push(args[++i]); }
37
+ else if (args[i] === "--or" && args[i + 1]) { flags.or.push(args[++i]); }
38
+ else if (args[i] === "--include" && args[i + 1]) { flags.include.push(args[++i]); }
39
+ else if (args[i] === "--skip" && args[i + 1]) { flags.skip.push(args[++i]); }
40
+ else if (args[i] === "--phase" && args[i + 1]) { flags.phase = args[++i]; }
41
+ else if (args[i] === "--index" && args[i + 1]) { flags.index = parseInt(args[++i], 10); }
42
+ else if (args[i] === "--header" && args[i + 1]) {
43
+ const val = args[++i];
44
+ const colonIdx = val.indexOf(":");
45
+ if (colonIdx !== -1) flags.headers[val.slice(0, colonIdx).trim()] = val.slice(colonIdx + 1).trim();
46
+ }
47
+ else if (args[i] === "--verbose") { flags.verbose = true; }
48
+ else if (args[i] === "--current") { flags.current = true; }
49
+ else if (args[i] === "--follow" || args[i] === "-f") { flags.follow = true; }
50
+ else if (args[i] === "--clear") { flags.clear = true; }
51
+ else if (args[i] === "--json") { flags.json = true; }
52
+ else if (args[i] === "--bail") { flags.bail = true; }
53
+ else if (args[i] === "--dry-run") { flags.dryRun = true; }
54
+ else if (args[i] === "--force") { flags.force = true; }
55
+ else if (args[i] === "--manifest") { flags.useManifest = true; }
56
+ else if (args[i] === "--saved") { flags.saved = true; }
57
+ else if (args[i] === "--save" && args[i + 1] && !args[i + 1].startsWith("-")) { flags.save = args[++i]; }
58
+ else if (args[i] === "--save") { flags.save = true; }
59
+ else if (args[i] === "--save-limit" && args[i + 1]) { flags.saveLimit = parseInt(args[++i], 10); }
60
+ else if (!args[i].startsWith("-")) { positional.push(args[i]); }
61
+ }
62
+ return { flags, positional };
63
+ };
64
+
65
+ const handleInput = async (input = "") => {
66
+ const parts = input.trim().split(/\s+/);
67
+ const command = parts[0];
68
+ if (!command) { lineReader.prompt(); return; }
69
+ const { flags, positional } = parseArgs(parts.slice(1));
70
+
71
+ if (["exit", "q"].includes(command)) {
15
72
  process.exit(0);
16
- } else if (command === "test") {
73
+ } else if (["stop", "shutdown"].includes(command)) {
74
+ const api = `${url}/systemview/api`;
17
75
  try {
18
- runTests(url, ...args);
19
- } catch (error) {
20
- console.error("Error executing tests:", error.message);
76
+ const { SystemView } = await Client.loadService(api);
77
+ await SystemView.shutdown();
78
+ } catch {}
79
+ const appIsRunning = require("./appIsRunning");
80
+ if (!(await appIsRunning(api))) {
81
+ log.success("SystemView stopped.");
82
+ process.exit(0);
83
+ } else {
84
+ log.error("Shutdown failed.");
85
+ lineReader.prompt();
21
86
  }
22
- } else if (command === "help") {
23
- cli.showHelp(0);
87
+ } else if (command === "test") {
88
+ try {
89
+ await runTests(url, positional[0], positional[1], {
90
+ headers: flags.headers,
91
+ json: flags.json,
92
+ verbose: flags.verbose,
93
+ bail: flags.bail,
94
+ dryRun: flags.dryRun,
95
+ phase: flags.phase,
96
+ index: flags.index,
97
+ skip: flags.skip,
98
+ });
99
+ } catch (e) { console.error(e.message); }
100
+ lineReader.prompt();
101
+ } else if (command === "list") {
102
+ try {
103
+ await listTests(url, positional[0], positional[1], {
104
+ connectedUrls,
105
+ verbose: flags.verbose,
106
+ });
107
+ } catch (e) { console.error(e.message); }
108
+ lineReader.prompt();
109
+ } else if (command === "logs") {
110
+ if (stopLogs) { stopLogs(); stopLogs = null; }
111
+ logsCommand(positional[0], positional[1], {
112
+ ...flags,
113
+ uiUrl: url,
114
+ }).then((stop) => { if (stop) stopLogs = stop; });
115
+ } else if (command === "stoplogs" || command === "unsubscribe") {
116
+ if (stopLogs) { stopLogs(); stopLogs = null; log.success("Log streaming stopped."); }
117
+ else { log.warn("No active log stream."); }
118
+ lineReader.prompt();
119
+ } else if (command === "clearlogs" || command === "flush") {
120
+ if (stopLogs) { stopLogs(); stopLogs = null; }
121
+ logsCommand(null, null, { clear: true, uiUrl: url });
122
+ lineReader.prompt();
123
+ } else if (command === "connect") {
124
+ try {
125
+ await connectService(positional[0], {
126
+ useManifest: flags.useManifest,
127
+ force: flags.force,
128
+ connectedUrls,
129
+ uiUrl: url,
130
+ });
131
+ } catch (e) { console.error(e.message); }
132
+ lineReader.prompt();
133
+ } else if (command === "disconnect") {
134
+ try {
135
+ await manifestCommands.disconnect(positional[0], positional[1], {
136
+ connectedUrls,
137
+ uiUrl: url,
138
+ });
139
+ } catch (e) { console.error(e.message); }
140
+ lineReader.prompt();
141
+ } else if (command === "manifest") {
142
+ const sub = positional[0];
143
+ try {
144
+ if (sub === "save") {
145
+ manifestCommands.save(undefined, undefined, {});
146
+ } else if (sub === "clean") {
147
+ await manifestCommands.clean();
148
+ } else {
149
+ console.log(" Usage: manifest <save|clean>");
150
+ }
151
+ } catch (e) { console.error(e.message); }
152
+ lineReader.prompt();
153
+ } else if (command === "probe") {
154
+ try {
155
+ await probe(positional[0], positional[1], { json: flags.json, headers: flags.headers, uiUrl: url });
156
+ } catch (e) { console.error(e.message); }
157
+ lineReader.prompt();
24
158
  } else if (command === "open") {
25
- openBrowser(url, ...args);
159
+ openBrowser(url, positional[0], positional[1]);
160
+ lineReader.prompt();
161
+ } else if (command === "help") {
162
+ cli.showHelp(false);
163
+ lineReader.prompt();
164
+ } else {
165
+ lineReader.prompt();
26
166
  }
27
- lineReader.prompt();
28
167
  };
29
168
 
30
169
  lineReader.prompt();
31
- lineReader.on("line", handleInput);
170
+ lineReader.on("line", async (input) => {
171
+ const trimmed = input.trim();
172
+ if (trimmed && CLI) {
173
+ try { await CLI.saveHistory(trimmed); } catch {}
174
+ }
175
+ handleInput(trimmed);
176
+ });
32
177
  lineReader.on("close", () => process.exit(0));
33
178
  return lineReader;
34
179
  };
package/cli/utils/cli.js CHANGED
@@ -8,23 +8,44 @@ const HELP_TEXT = `
8
8
  start [port] Launch SystemView UI (default port 3000)
9
9
  test <projectCode> [namespace] Run saved tests for a project
10
10
  list [projectCode] [namespace] List projects, services, or tests
11
- connect <serviceId> <url> Register a service and write manifest
12
- connect Re-probe all services in existing manifest
13
- probe <ServiceId.Module.method> [args] Call a method ad-hoc
11
+ logs [projectCode] [namespace] Stream log entries from connected services
12
+ unsubscribe Stop streaming logs (keeps log file) [alias: stoplogs]
13
+ flush Wipe the log file and stop streaming [alias: clearlogs]
14
+ connect [url|projectCode] Connect a service URL, reconnect a stored project, or connect all
15
+ connect <url> --manifest Connect via plugin manifest — registers under real projectCode
16
+ disconnect [projectCode] [serviceId] Remove a project or service from the UI store
17
+ manifest clean Re-probe manifest entries, remove stale ones
18
+ probe <ServiceId.Module.method> [args] Call a service method ad-hoc
14
19
  open [projectCode] [namespace] Open the browser UI
15
- shutdown [port] Stop a running SystemView instance
20
+ shutdown [port] Stop a running SystemView instance [aliases: exit, stop, q]
16
21
 
17
22
  Flags:
18
23
  --version Print version and exit
24
+ -d, --debug Verbose debug output
19
25
  --json Output results as JSON (for agents/CI)
20
- --verbose test: full results and args for all phases; list: expand to show methods and test titles
21
- --manifest <path> Path to manifest file (default: ./systemview.manifest.json)
22
- --header "Name: Value" Extra request header (repeatable; overrides manifest.probeHeaders)
26
+ --verbose test: full results and args for all phases; list: expand hierarchy
27
+ --manifest connect: use plugin manifest to get real projectCode
28
+ --manifest <path> probe: path to manifest file (default: ./systemview.manifest.json)
29
+ --header "Name: Value" Extra request header (repeatable)
23
30
  --skip <pattern> Exclude tests matching pattern (repeatable)
24
31
  --bail Stop after first failure
25
32
  --dry-run Print which tests would run without executing
26
33
  --phase <before|main|events|after> Run only specified phase(s), comma-separated
27
34
  --index <n> Run only action at index n within each phase (0-based)
35
+ --level <trace|log|warn|error|debug> logs: filter by level
36
+ --limit <n> logs: max entries to show with --current (default 50)
37
+ --current logs: show existing entries (use --follow to also stream)
38
+ -f, --follow logs: keep streaming after --current
39
+ --clear logs: wipe log store then stream
40
+ --filter <field=value> logs: AND filter on a field (repeatable); field can be a dot path
41
+ --filter has=<field> → only entries where field is present
42
+ --filter missing=<field> → only entries where field is absent
43
+ --or <field=value> logs: OR filter on a field (repeatable)
44
+ --include <field> logs: include extra field as a column (repeatable)
45
+ --save [path] logs: append streamed entries to a local snapshot file
46
+ --saved logs: read from local snapshot instead of live service
47
+ --save-limit <n> logs: max entries to keep in snapshot (default 500)
48
+ --force connect: re-probe even if already connected
28
49
 
29
50
  Examples:
30
51
  systemview start
@@ -35,8 +56,19 @@ const HELP_TEXT = `
35
56
  systemview list
36
57
  systemview list buAPI
37
58
  systemview list buAPI --verbose
38
- systemview list buAPI signUp
39
- systemview connect ProfilesService http://localhost:4100/bu/api/profiles
59
+ systemview logs buAPI
60
+ systemview logs buAPI --current --limit 20
61
+ systemview logs buAPI --current --follow
62
+ systemview logs buAPI --filter level=error
63
+ systemview logs buAPI --filter has=log.userId
64
+ systemview logs buAPI --filter missing=error --include log
65
+ systemview logs buAPI --save
66
+ systemview logs buAPI --saved
67
+ systemview connect http://localhost:4100/bu/api/profiles
68
+ systemview connect http://localhost:4100/bu/api/profiles --manifest
69
+ systemview connect buAPI
70
+ systemview disconnect buAPI
71
+ systemview disconnect buAPI ProfilesService
40
72
  systemview probe ProfilesService.Users.getUser '{"userId":"123"}'
41
73
  systemview open buAPI signUp
42
74
  systemview test buAPI --header "X-Api-Key: secret"
@@ -44,7 +76,7 @@ const HELP_TEXT = `
44
76
 
45
77
  const rawArgs = process.argv.slice(2);
46
78
 
47
- const flagValueArgs = ["--manifest", "--header", "--skip", "--phase", "--index"];
79
+ const flagValueArgs = ["--manifest", "--header", "--skip", "--phase", "--index", "--level", "--limit", "--follow", "--filter", "--or", "--include", "--save", "--save-limit"];
48
80
 
49
81
  const flags = {
50
82
  json: rawArgs.includes("--json"),
@@ -73,6 +105,48 @@ const flags = {
73
105
  });
74
106
  return result;
75
107
  })(),
108
+ level: (() => {
109
+ const i = rawArgs.indexOf("--level");
110
+ return i !== -1 ? rawArgs[i + 1] : null;
111
+ })(),
112
+ limit: (() => {
113
+ const i = rawArgs.indexOf("--limit");
114
+ if (i === -1) return undefined;
115
+ const val = parseInt(rawArgs[i + 1], 10);
116
+ return isNaN(val) ? undefined : val;
117
+ })(),
118
+ follow: rawArgs.includes("--follow") || rawArgs.includes("-f"),
119
+ current: rawArgs.includes("--current"),
120
+ filter: (() => {
121
+ const result = [];
122
+ rawArgs.forEach((a, i) => { if (a === "--filter" && rawArgs[i + 1]) result.push(rawArgs[i + 1]); });
123
+ return result;
124
+ })(),
125
+ or: (() => {
126
+ const result = [];
127
+ rawArgs.forEach((a, i) => { if (a === "--or" && rawArgs[i + 1]) result.push(rawArgs[i + 1]); });
128
+ return result;
129
+ })(),
130
+ include: (() => {
131
+ const result = [];
132
+ rawArgs.forEach((a, i) => { if (a === "--include" && rawArgs[i + 1]) result.push(rawArgs[i + 1]); });
133
+ return result;
134
+ })(),
135
+ clear: rawArgs.includes("--clear"),
136
+ force: rawArgs.includes("--force"),
137
+ save: (() => {
138
+ const i = rawArgs.indexOf("--save");
139
+ if (i === -1) return false;
140
+ const next = rawArgs[i + 1];
141
+ return (next && !next.startsWith("-")) ? next : true;
142
+ })(),
143
+ saved: rawArgs.includes("--saved"),
144
+ saveLimit: (() => {
145
+ const i = rawArgs.indexOf("--save-limit");
146
+ if (i === -1) return 500;
147
+ const val = parseInt(rawArgs[i + 1], 10);
148
+ return isNaN(val) ? 500 : val;
149
+ })(),
76
150
  headers: (() => {
77
151
  const result = {};
78
152
  rawArgs.forEach((a, i) => {
@@ -97,8 +171,8 @@ const input = rawArgs.filter((a, i) => {
97
171
  module.exports = {
98
172
  input,
99
173
  flags,
100
- showHelp() {
174
+ showHelp(exit = true) {
101
175
  console.log(HELP_TEXT);
102
- process.exit(0);
176
+ if (exit) process.exit(0);
103
177
  },
104
178
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "systemview",
3
3
  "description": "A documentation and testing suite for SystemLynx",
4
- "version": "1.20.1",
4
+ "version": "1.22.0",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
7
7
  "systemview": "cli/index.js"
@@ -16,8 +16,8 @@
16
16
  "chalk": "^4.1.2",
17
17
  "express": "^4.18.2",
18
18
  "moment": "^2.29.1",
19
- "systemlynx": "^1.19.12",
20
- "systemlynx-client": "^1.19.14",
19
+ "systemlynx": "^2.0.0",
20
+ "systemlynx-client": "^2.0.0",
21
21
  "web-vitals": "^0.2.4"
22
22
  },
23
23
  "scripts": {
@@ -13,6 +13,7 @@ module.exports = function Test({
13
13
  editMode = true,
14
14
  logger,
15
15
  client,
16
+ extraHeaders,
16
17
  }) {
17
18
  this.index = index;
18
19
  this.connection = {};
@@ -101,7 +102,7 @@ module.exports = function Test({
101
102
  const { connectionData } = service.system;
102
103
 
103
104
  this.connection[serviceId] = (client || Client).createService(connectionData);
104
- this.connection[serviceId].setHeaders({ Origin: `http://localhost:${3000}` });
105
+ this.connection[serviceId].setHeaders({ Origin: `http://localhost:${3000}`, ...(extraHeaders || {}) });
105
106
  }
106
107
 
107
108
  return this;
@@ -1,23 +1,23 @@
1
1
  const { Argument } = require("./Argument.class");
2
2
  const Test = require("./Test.class");
3
3
 
4
- function initializeSavedTests(savedTests, connectedServices, client) {
4
+ function initializeSavedTests(savedTests, connectedServices, client, extraHeaders) {
5
5
  return savedTests.map((ft) => {
6
6
  // context matters
7
7
  const newTests = [];
8
8
  const { title, namespace } = ft;
9
9
 
10
10
  const Before = ft.Before.map((test) =>
11
- resetTestClass(test, newTests, connectedServices, false, client)
11
+ resetTestClass(test, newTests, connectedServices, false, client, extraHeaders)
12
12
  );
13
13
  const Main = ft.Main.map((test) =>
14
- resetTestClass(test, newTests, connectedServices, false, client)
14
+ resetTestClass(test, newTests, connectedServices, false, client, extraHeaders)
15
15
  );
16
16
  const Events = ft.Events.map((test) =>
17
- resetTestClass(test, newTests, connectedServices, false, client)
17
+ resetTestClass(test, newTests, connectedServices, false, client, extraHeaders)
18
18
  );
19
19
  const After = ft.After.map((test) =>
20
- resetTestClass(test, newTests, connectedServices, false, client)
20
+ resetTestClass(test, newTests, connectedServices, false, client, extraHeaders)
21
21
  );
22
22
  newTests.push(Before);
23
23
  newTests.push(Main);
@@ -27,7 +27,7 @@ function initializeSavedTests(savedTests, connectedServices, client) {
27
27
  });
28
28
  }
29
29
 
30
- const resetTestClass = (test, FullTest, connectedServices, editMode, client) => {
30
+ const resetTestClass = (test, FullTest, connectedServices, editMode, client, extraHeaders) => {
31
31
  return new Test({
32
32
  ...test,
33
33
  args: test.args.map(
@@ -36,6 +36,7 @@ const resetTestClass = (test, FullTest, connectedServices, editMode, client) =>
36
36
  ),
37
37
  editMode,
38
38
  client,
39
+ extraHeaders,
39
40
  }).getConnection(connectedServices);
40
41
  };
41
42
 
@@ -1,15 +0,0 @@
1
- @font-face{font-family:SF Mono;src:url(/static/media/FontsFree-Net-SFMono-Regular.9647425ef282c28529df.ttf) format("ttf")}@font-face{font-family:Malkor;src:url(/static/media/Malkor-Regular.f55d6a829566789554a5.ttf) format("ttf")}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;margin:0}code{font-family:SF Mono,system-ui,source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace}
2
-
3
- /*!
4
- * Bootstrap Grid v4.0.0 (https://getbootstrap.com)
5
- * Copyright 2011-2018 The Bootstrap Authors
6
- * Copyright 2011-2018 Twitter, Inc.
7
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
8
- */.textbox{flex:1 1}.textbox input,.textbox textarea{font-size:15px;padding:7px;width:100%}.link{color:#282d33;font-size:16px;text-decoration:none}.link:hover{text-decoration:underline}.expandable-list{text-indent:10px}.expandable-list__items--hidden{display:none}.expandable-list__button{display:flex;text-align:left}.expandable-list__button a,.expandable-list__button>span{align-items:center;display:flex}.list{color:#343542;display:flex;flex-direction:column;line-height:20px;padding:6px 0 6px 6px;text-align:left;text-indent:29px}.expandable-icon{cursor:pointer;font-family:sans-serif;font-size:11px}.server-module__methods{display:flex}.server-module__methods--selected-true{background:linear-gradient(90deg,#deefe8 69%,#fff);background:linear-gradient(90deg,#d8d7e9 69%,#fff);border-radius:5px 2px 2px 5px;font-weight:700}.server-module__methods--selected-true>a{color:#575fc1}.server-module__docs-icon{display:inline;margin-left:auto}.server-module__docs-icon img{width:23px!important}.server-module__name--plugin a{color:#4caf50;font-weight:700}.system-nav{max-height:100vh;overflow:auto;padding:3rem 1rem}.system-nav__section{margin:21px 10px}.system-nav__object-title{display:inline}.system-nav__service-url{color:#3f51b5;color:#607d8b!important;display:block!important;font-size:13px;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;width:230px}.system-nav__link{margin-left:3px;width:100%}.system-nav__link--selected-true{background:linear-gradient(90deg,#deefe8 69%,#fff);background:linear-gradient(90deg,#d8d7e9 69%,#fff);border-radius:5px 2px 2px 5px}.system-nav__link--selected-true>a{color:#575fc1!important;font-weight:700}.documentation-view{color:#000;padding-top:2rem}.documentation-view__parameter{color:#3dceac;font-weight:700}.documentation-view__data-table{margin-bottom:30px}.documentation-view__title{align-items:flex-start;color:#454c69;display:flex;margin-left:4px}.documentation-view__parentheses{font-size:26px}.description-box{width:100%}.description-box__textbox{background:#fff;border:none;border-bottom:1px solid #07625a;border-radius:2px;color:#000;font-size:13px;font-size:15px;font-weight:500;max-width:100%;min-height:70vh;min-width:100%;outline:none;padding:38px;resize:none}.edit-box{background:#fff;border:2px solid #f1f1f1;border-radius:13px;max-height:80vh;overflow:scroll;width:100%}.edit-box--read:hover{border:2px dashed #8b97ba;cursor:pointer}.edit-box__main{border:2px dashed #0000}.edit-box__form--hidden,.edit-box__main--hidden{display:none}.edit-box__button{display:flex;flex-direction:row;justify-content:flex-end;padding:6px 15px;width:100%}.button{background:linear-gradient(180deg,#f9f9f9 5%,#e9e9e9);border:1px solid;border-radius:3px;color:#666;cursor:pointer;display:inline-block;font-family:Arial;font-size:15px;font-weight:700;margin:4px 10px;padding:6px 24px;text-decoration:none;text-shadow:0 1px 0 #fff}.button:hover{background:linear-gradient(180deg,#e9e9e9 5%,#f9f9f9);background-color:#e9e9e9}.button:active{position:relative;top:1px}.clear-button{align-self:flex-end;background:#607d8b;border-radius:17px;color:#fff;font-weight:600;padding:0 8px}.clear-button>img{padding-top:2px;width:13px}.title{color:#0e886b;font-family:sans-serif;font-size:28px;position:relative}.markdown{background-color:#fff;font-size:15px;line-height:1.6;padding:30px}.markdown>:first-child{margin-top:0!important}.markdown>:last-child{margin-bottom:0!important}.markdown a{color:#4183c4}.markdown a.absent{color:#c00}.markdown a.anchor{bottom:0;cursor:pointer;display:block;left:0;margin-left:-30px;padding-left:30px;position:absolute;top:0}.markdown h1,.markdown h2,.markdown h3,.markdown h4,.markdown h5,.markdown h6{-webkit-font-smoothing:antialiased;color:#5960b6!important;cursor:text;font-weight:700;margin:20px 0 10px;padding:0;position:relative}.markdown h1:hover a.anchor,.markdown h2:hover a.anchor,.markdown h3:hover a.anchor,.markdown h4:hover a.anchor,.markdown h5:hover a.anchor,.markdown h6:hover a.anchor{text-decoration:none}.markdown h1 code,.markdown h1 tt,.markdown h2 code,.markdown h2 tt,.markdown h3 code,.markdown h3 tt,.markdown h4 code,.markdown h4 tt,.markdown h5 code,.markdown h5 tt,.markdown h6 code,.markdown h6 tt{font-size:inherit}.markdown h1{color:#000;font-size:28px}.markdown h2{border-bottom:1px solid #ccc;color:#000;font-size:24px}.markdown h3{font-size:18px}.markdown h4{font-size:16px}.markdown h5,.markdown h6{font-size:14px}.markdown h6{color:#777}.markdown blockquote,.markdown dl,.markdown li,.markdown ol,.markdown p,.markdown pre,.markdown table,.markdown ul{margin:15px 0}.markdown hr{border:0;border-bottom:1px solid;color:#ccc;height:4px;padding:0}.markdown a:first-child h1,.markdown a:first-child h2,.markdown a:first-child h3,.markdown a:first-child h4,.markdown a:first-child h5,.markdown a:first-child h6,.markdown>h1:first-child,.markdown>h1:first-child+h2,.markdown>h2:first-child,.markdown>h3:first-child,.markdown>h4:first-child,.markdown>h5:first-child,.markdown>h6:first-child{margin-top:0;padding-top:0}.markdown h1 p,.markdown h2 p,.markdown h3 p,.markdown h4 p,.markdown h5 p,.markdown h6 p{margin-top:0}.markdown li p.first{display:inline-block}.markdown li{margin:0}.markdown ol,.markdown ul{padding-left:30px}.markdown ol :first-child,.markdown ul :first-child{margin-top:0}.markdown dl{padding:0}.markdown dl dt{font-size:14px;font-style:italic;font-weight:700;margin:15px 0 5px;padding:0}.markdown dl dt:first-child{padding:0}.markdown dl dt>:first-child{margin-top:0}.markdown dl dt>:last-child{margin-bottom:0}.markdown dl dd{margin:0 0 15px;padding:0 15px}.markdown dl dd>:first-child{margin-top:0}.markdown dl dd>:last-child{margin-bottom:0}.markdown blockquote{border-left:3px solid #c3c3c3;color:#777;font-size:14px;text-indent:8px}.markdown blockquote>:first-child{margin-top:0}.markdown blockquote>:last-child{margin-bottom:0}.markdown table{border-collapse:collapse;padding:0}.markdown table tr{background-color:#fff;border-top:1px solid #ccc;margin:0;padding:0}.markdown table tr:nth-child(2n){background-color:#f8f8f8}.markdown table tr th{font-weight:700}.markdown table tr td,.markdown table tr th{border:1px solid #ccc;margin:0;padding:6px 13px}.markdown table tr td :first-child,.markdown table tr th :first-child{margin-top:0}.markdown table tr td :last-child,.markdown table tr th :last-child{margin-bottom:0}.markdown img{max-width:100%}.markdown span.frame,.markdown span.frame>span{display:block;overflow:hidden}.markdown span.frame>span{border:1px solid #ddd;float:left;margin:13px 0 0;padding:7px;width:auto}.markdown span.frame span img{display:block;float:left}.markdown span.frame span span{clear:both;color:#333;display:block;padding:5px 0 0}.markdown span.align-center{clear:both;display:block;overflow:hidden}.markdown span.align-center>span{display:block;margin:13px auto 0;overflow:hidden;text-align:center}.markdown span.align-center span img{margin:0 auto;text-align:center}.markdown span.align-right{clear:both;display:block;overflow:hidden}.markdown span.align-right>span{display:block;margin:13px 0 0;overflow:hidden;text-align:right}.markdown span.align-right span img{margin:0;text-align:right}.markdown span.float-left{display:block;float:left;margin-right:13px;overflow:hidden}.markdown span.float-left span{margin:13px 0 0}.markdown span.float-right{display:block;float:right;margin-left:13px;overflow:hidden}.markdown span.float-right>span{display:block;margin:13px auto 0;overflow:hidden;text-align:right}.markdown code,.markdown tt{background-color:#efeeee;border-radius:3px;color:#3f51b5;font-size:14px;margin:0 2px;padding:2px 3px;white-space:nowrap}.markdown pre code{background:#0000;border:none;margin:0;padding:0;white-space:pre}.markdown .highlight pre,.markdown pre{font-size:13px}.markdown pre code,.markdown pre tt{background-color:#0000;border:none}.markdown sup{font-size:.83em;line-height:0;vertical-align:super}.markdown *{-webkit-print-color-adjust:exact}@media screen and (min-width:914px){.markdown body{margin:0 auto;width:854px}}@media print{.markdown pre,.markdown table{page-break-inside:avoid}.markdown pre{word-wrap:break-word}}.expandable-section{margin-bottom:6px;width:100%}.expandable-section__items--hidden{display:none}.expandable-section__title{display:flex;margin-bottom:7px;position:relative}.expandable-section__title__btn{cursor:pointer}.expandable-section__btn--hide-true{visibility:hidden}.test-caption{align-items:center;display:flex;font-family:sans-serif;font-size:16px;font-weight:400;margin:0 4px;padding:0 8px;width:100%}.test-caption__title{color:#0d8065}.test-caption__description-input{flex:1 1;padding-left:5px}.test-caption__description-input input{background:#e9e9e9;border:none;border-radius:41px;color:#676767;font-size:16px;line-height:19px;text-indent:10px;text-overflow:ellipsis;width:104%}.test-caption__description-input input::placeholder{color:#bebebe;font-style:italic;font-weight:400}.test-caption__description-input--visible-false{display:none}.auto-complete{display:inline;display:initial;position:relative}.auto-complete__suggestions{box-shadow:1px 3px 4px #736c6c;display:grid;font-family:monospace;left:0;max-height:365px;overflow-y:auto;position:absolute;top:19px;z-index:1}.auto-complete__suggestion{background:#fff;cursor:pointer;display:inline-flex;padding:6px 7px;width:calc(300px + 1rem)}.auto-complete__suggestion--active,.auto-complete__suggestion:hover:not(.auto-complete__suggestion--empty){background-color:#cbcbff;background-color:#dadaed;color:#5960b6;color:#3f495d;font-weight:100;font-weight:700}.auto-complete__suggestion--empty{justify-content:center}.json-text-box{position:relative}.json-text-box__textbox{border:1px solid #8ea8eb;margin-top:6px;max-width:100%;min-height:100px;min-width:100%}.json-text-box__btn-container{position:absolute;right:1px;top:9px}.json-text-box__btn{border-radius:1px;cursor:pointer;font-family:system-ui;font-weight:500;margin-left:4px;padding:2px 6px}.json-text-box__btn:active{position:relative;top:1px}.json-text-box__btn--is-json-true{background:#25d0a8;color:#fff}.json-text-box__btn--is-json-false{background:#cfc2c2;color:#8c3c3c;text-decoration:line-through}.json-text-box__btn--cancel{background:#ff6b6b;color:#fff}.type-selector{-webkit-appearance:none;appearance:none;background:none;border:none;color:blue;cursor:pointer;font-family:SF Mono,monospace;outline:none}.switch{display:inline-block;height:33px;position:relative;width:60px}.switch input{height:0;opacity:0;width:0}.slider{background-color:#a78686;background-color:#6e6e78;bottom:0;cursor:pointer;left:0;right:0;top:0}.slider,.slider:before{position:absolute;transition:.4s}.slider:before{background-color:#fff;bottom:4px;content:"";height:26px;left:4px;width:26px}input:checked+.slider{background-color:#29ab8c}input:focus+.slider{box-shadow:0 0 1px #29ab8c}input:checked+.slider:before{transform:translateX(26px)}.slider.round{border-radius:34px}.slider.round:before{border-radius:50%}.args{display:inline;width:100%}.args__add-btn{background:#5a77e5;border-radius:21px;color:#fff;font-family:monospace;font-size:16px;font-weight:700;line-height:16px;margin:0 5px;padding:0 3px}.args__data{background:#cecee3;border-radius:7px;margin:2px;padding:11px;position:relative}.args__data__delete-btn{border-radius:0 7px 0 0!important;padding:0 5px 1px!important;right:0!important;top:0!important}.args__name{white-space:nowrap}.args__name__text{background:#5a77e5;border-radius:100px;color:#fff;cursor:pointer;display:inline-block;font-weight:700;margin:1px 0;padding:2px 10px}.args__from-container{display:flex}.args__form--is12{margin-top:10px}.args__form__undefined{color:#5a5a5a}.args__form__input{background:none;border:none;border-bottom:1px solid #9797d1;font-family:monospace;font-size:14px}.args__form__input--number{color:#9741ed;font-weight:700}.args__form__input--string,.args__form__input--target{color:#cf5f2e;font-style:italic;height:31px;max-height:320px;max-width:100%;min-height:31px;min-width:100%;text-indent:5px}.args__form__input--target{color:#009572;font-weight:700}.args__form__input--date{color:#9f4040;margin-top:6px}.args__form__value--boolean{font-weight:700;position:relative;top:7px}.args__form__value--boolean--true{color:#2eab8c;margin-right:5px}.args__form__value--boolean--false{color:#d52518}.args__quote{color:#209cff;font-size:21px;line-height:1px}.args__type{text-align:center}.args__name-display{display:inline-block;margin-right:4px}.args__expand-btn{color:#0035cf61;text-shadow:1px 1px 1px #cfcfcf}.args__add-json-btn{border-radius:2px;color:#0d8065;padding:2px 3px;position:absolute;right:0;top:6px}.args__add-json-btn:hover{text-decoration:underline}.args__json-txb--show-false{display:none!important}.args__value{padding:14px}.args__value--hide{display:none}.args__value__number{color:#9741ed;font-weight:700}.args__value__string{color:#cf5f2e;white-space:pre-line}.args__value__date{color:#9f4040}.args__value__undefined{color:#5a5a5a}.args__value__object{padding:0}.args__value__boolean{font-weight:700}.args__value__boolean--true{color:#207844}.args__value__boolean--false{color:#cf1515}.scratchpad{--text-length:auto;overflow-wrap:anywhere;width:100%}.scratchpad__test-data-container{position:relative;width:100%}.scratchpad__test-data{background:#e9e9e9;border-radius:5px 5px 0 0;padding:25px 15px}.scratchpad__test-data__parentheses{font-size:19px}.scratchpad__response-data{background:#fff;border-left:1px solid #e9e9e9;border-right:1px solid #e9e9e9;padding:12px 15px;position:relative}.scratchpad__response-data--visible-false{display:none}.scratchpad__response-data__clear-btn{color:#c50000;font-family:sans-serif;position:absolute;right:9px;top:5px}.scratchpad__response-value{align-items:flex-start;color:#a954ff;display:flex;flex-wrap:wrap;font-family:FS Mono,monospace;font-weight:500;margin:5px 0 0 5px}.scratchpad__response-value span.collapsed-icon{left:7px;position:relative;top:2px}.scratchpad__response-type{color:#a954ff;font-size:15px;font-weight:700}.scratchpad__btn-container{position:absolute;right:4px;top:4px}.scratchpad__btn-container>span{margin:0 5px}.scratchpad__run-test-btn{cursor:pointer}.scratchpad__test-method-input{background:none;border:none;color:#223a95;font-family:SF Mono,monospace;font-size:17px;max-width:100%;text-indent:0;text-overflow:clip;width:var(--text-length)}.scratchpad__test-method-input:focus{background:#fff}.scratchpad__eval-btn{bottom:3px;color:#3f51b5;font-size:15px;font-weight:700;position:absolute;right:7px}.doc-icon{display:inline-flex;vertical-align:middle}.doc-icon img{width:20px}.delete-button{background:#fff;border-radius:40px;color:#c50000;font-family:system-ui;font-weight:300;padding:6px 3px}.error-message{color:#ff5722;font-family:monospace;padding:4px 25px;word-break:break-word}.error-message__message-container{background:#ededed}.error-message__message{background:#ededed;border-radius:5px;padding:6px 23px}.error-message__namespace{color:#b136c6;font-weight:600}.error-message__expected{color:#0b8b22;font-weight:700}.validation-input{display:flex;margin:3px 0}.validation-input__input,.validation-input__selector{background:none;border:none;font-family:monospace;font-size:14px}.validation-input__selector{-webkit-appearance:none;appearance:none;border-right:none;color:#009688;cursor:pointer;font-weight:700;outline:none;padding:3px;text-indent:5px}.validation-input__selector:hover{background:#b3c1e8;border-radius:33px}.validation-input__input{color:#0d8065;outline:none;padding:4px}.validation-input__value--boolean{font-weight:700;position:relative;top:7px}.validation-input__value--boolean--true{color:#207844}.validation-input__value--boolean--false{color:#cf1515}input:-webkit-autofill{border:3px solid blue}input:autofill{border:3px solid blue}.count{background:#dcdcdc;border-radius:12px;color:#777!important;font-size:14px;font-weight:700;margin-left:5px;padding:0 9px}.count,.count__stat{display:inline-block}.count__stat{padding:3px 0}.count__error{background:#ffc4b1;color:#f44336!important}.count__caution{color:#bcb047!important}.count__passed{background:#6fc878;color:#fff!important}.test-container__title-section{display:flex;font-size:16px;margin:0 4px;padding:0 8px;width:100%}.test-container__test-description-input{flex:1 1}.test-container__test-description-input input{background:none;border:none;color:#5a77e5;font-weight:700;text-overflow:ellipsis;width:105%}.multi-test-section{width:100%}.multi-test-section__test-data{background:#dadada;border-radius:5px;padding:12px 15px;width:100%}.multi-test-section__add-btn{background:#cecee3;border-radius:21px;color:#5960b6;font-family:monospace;font-size:16px;font-weight:700;padding:0 4px}.evaluations{background:#25d0a8;background:#76b1f7;background:#ced8f4;border-radius:0 0 4px 4px;font-family:monospace;overflow-wrap:anywhere;padding:12px 18px}.evaluations--visible-false{display:none}.evaluations__row{margin:4px;padding:8px 5px}.evaluations__title{--type-width:auto;margin-left:10px;width:100%}.evaluations__title select{width:var(--type-width)}.evaluations__input>input{background:#a5ffda;border:1px solid #383836;box-sizing:border-box;margin:8px 0;padding:6px 9px;width:100%}.evaluations__input--visible-false{display:none}.evaluations__add-validation-btn{background:#5a77ca;border-radius:16px;color:#fff;font-weight:700;padding:0 5px 1px}.evaluations__validation-container{display:inline-grid;margin-left:4px}.evaluations__add-btn-container{display:inline-grid}.evaluations__validation{border-bottom:1px solid #9797d1}.evaluations__validation__delete-btn{color:#6565a1;display:inline;font-family:system-ui;font-size:15px;margin-left:6px}.evaluations__validation__delete-btn:hover{color:#c30f0f}.evaluations__validation__input{display:inline-flex}.evaluations__type-error-msg{display:none}.evaluations__type-error-msg--true{display:inline;display:initial}.evaluations--error-true,.evaluations--error-true>*{color:#cd4343;font-weight:700}.evaluations__total{color:gray}.evaluations__checkbox{cursor:pointer}.evaluations__index-button{align-items:center;display:flex;flex-direction:row}.evaluations__index-button.btn:hover{color:#2326fe;color:#ff5722;color:#c717e5;color:#1131df;font-weight:700}.evaluations__index-button--indexed-true{font-weight:700}.evaluations__namespace{display:inline-flex;flex-wrap:wrap}.evaluations__index-input{height:15px;width:45px}.evaluations__brackets{align-self:baseline;color:#000;font-size:14px;font-weight:700}.evaluations__index-checkbox{cursor:pointer}.evaluations__random{align-self:baseline;color:#2b9b2c;font-style:italic;font-weight:700}.evaluations__clear-error{color:gray;font-size:16px}.evaluations__clear-error:hover{color:#000}.evaluations__add-index-btn{color:#2776ff;font-size:16px;font-weight:700}.test__buttons{justify-content:space-between;margin-bottom:3px}.test__buttons>span>span{margin:0 5px}.test__buttons>span{background:#e9e9e9;border-radius:41px;font-family:Helvetica,arial,sans-serif;margin-right:3px;padding:2px 11px}.test-panel{font-size:14px;max-height:100vh;overflow:auto;padding:2rem 1rem}.test-panel__section{margin-bottom:6px}.test-panel__section>section{width:100%}.test-panel__error-message{align-items:center;background:#d4d4d4;color:#c02a2a;display:flex;font-weight:700;padding:2px 8px!important}.test-panel__error-message--hide-true{opacity:0}.test-panel__error-message--error-false{color:green}.save-icon{height:16px}.test-summary{border:1px solid #dfdfdf;border-bottom:1px solid #e8e8e8;border-top:none;padding:8px 5px}.test-summary:last-child{border-bottom:1px solid #dfdfdf}.test-summary__actions{display:flex;font-weight:300;padding:3px 0}.test-summary__action-text{flex:1 1}.test-summary__method{align-items:flex-start;color:#a954ff;display:flex;flex-wrap:wrap;font-family:FS Mono,monospace;font-weight:500;margin-bottom:10px;margin-left:10px}.test-summary__method span.collapsed-icon{left:7px;position:relative;top:2px}.test-summary__validations .expandable-icon{align-self:flex-end;margin-left:3px}.test-summary__failed-validations{color:#ff5722;font-family:monospace;padding:4px 25px}.test-summary__failed-validations--namespace{color:#a954ff;font-weight:700}.test-summary__header{align-items:center;display:flex}.test-summary__parameter{background:#fff;border:1px solid #fce8ff;border-radius:4px;display:inline-flex}.test-summary__comma{align-self:flex-end;color:green;font-size:17;font-weight:700;margin-right:3px}.test-summary__parentheses{align-self:flex-end;font-size:15px;font-weight:bolder;position:relative;top:-1px}.test-summary__results{color:#a954ff;font-weight:700}.test-summary__arrow{margin-right:10px}.test-summary__caption--Main{font-weight:700}.test-saved-section{border-top:1px solid #e9e9e9;padding-top:10px;width:100%}.test-saved-section__test-data{background:#dcdcdc;padding:12px 15px;width:100%}.test-saved-section__test-container{margin:5px 0}.test-saved-section__test-row{align-items:center;background:#e9e9e9;border:1px solid #e9e9e9;display:flex;padding:4px 5px}.test-saved-section__test-index{color:#3d3d3d;flex:1 1;font-size:14px;font-weight:600;padding:0 8px}.test-saved-section__test-title{color:#236382;flex:5 1}.test-saved-section__buttons{align-items:center;display:flex;flex:2 1;flex-direction:row;justify-content:space-around}.test-saved-section__top-buttons{flex:none;width:77px}.test-saved-section__clear-button{align-self:flex-end;background:#607d8b;border-radius:17px;color:#fff;font-weight:600;padding:0 8px}.test-saved-section__clear-button>img{padding-top:2px;width:13px}.test-saved-section__delete-prompt{color:#c02a2a;font-weight:700}.test-saved-section__delete-btn{background:gray;border-radius:4px;color:#fff;margin:0 5px;padding:0 6px}.test-saved-section__delete-btn--yes:hover{color:#c02a2a}.react-json-view{font-size:14px}.status-indicator{align-items:center;align-self:center;background:#22886b;background:#292936;border-radius:41px;color:#e9e9e9;color:#3bcaa1;display:flex;font-family:sans-serif;font-weight:500;font-weight:700;line-height:19px;margin:0 5px;padding:3px 0;text-align:center;text-overflow:ellipsis}.status-indicator__title{padding:0 13px}.status-indicator__clear-button{border-radius:0 40px 40px 0;color:#fff;display:flex!important;font-family:system-ui;padding:0 11px 1px 0}.status-indicator__clear-button:hover{color:#f10;font-weight:300}
9
- /*!
10
- * Bootstrap Grid v4.0.0 (https://getbootstrap.com)
11
- * Copyright 2011-2018 The Bootstrap Authors
12
- * Copyright 2011-2018 Twitter, Inc.
13
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
14
- */html{-ms-overflow-style:scrollbar;box-sizing:border-box}*,:after,:before{box-sizing:inherit}.container{margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px;width:100%}@media(min-width:576px){.container{max-width:540px}}@media(min-width:768px){.container{max-width:720px}}@media(min-width:992px){.container{max-width:960px}}@media(min-width:1200px){.container{max-width:1140px}}.container-fluid{margin-left:auto;margin-right:auto;padding-left:15px;padding-right:15px;width:100%}.row{display:flex;flex-wrap:wrap;margin-left:-15px;margin-right:-15px}.no-gutters{margin-left:0;margin-right:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-left:0;padding-right:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{min-height:1px;padding-left:15px;padding-right:15px;position:relative;width:100%}.col{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex:0 0 auto;max-width:none;width:auto}.col-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-3{flex:0 0 25%;max-width:25%}.col-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-6{flex:0 0 50%;max-width:50%}.col-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-9{flex:0 0 75%;max-width:75%}.col-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-12{flex:0 0 100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.3333333333%}.offset-2{margin-left:16.6666666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.3333333333%}.offset-5{margin-left:41.6666666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.3333333333%}.offset-8{margin-left:66.6666666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.3333333333%}.offset-11{margin-left:91.6666666667%}@media(min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex:0 0 auto;max-width:none;width:auto}.col-sm-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-sm-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-sm-3{flex:0 0 25%;max-width:25%}.col-sm-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-sm-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-sm-6{flex:0 0 50%;max-width:50%}.col-sm-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-sm-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-sm-9{flex:0 0 75%;max-width:75%}.col-sm-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-sm-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-sm-12{flex:0 0 100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.3333333333%}.offset-sm-2{margin-left:16.6666666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.3333333333%}.offset-sm-5{margin-left:41.6666666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.3333333333%}.offset-sm-8{margin-left:66.6666666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.3333333333%}.offset-sm-11{margin-left:91.6666666667%}}@media(min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex:0 0 auto;max-width:none;width:auto}.col-md-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-md-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-md-3{flex:0 0 25%;max-width:25%}.col-md-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-md-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-md-6{flex:0 0 50%;max-width:50%}.col-md-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-md-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-md-9{flex:0 0 75%;max-width:75%}.col-md-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-md-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-md-12{flex:0 0 100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.3333333333%}.offset-md-2{margin-left:16.6666666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.3333333333%}.offset-md-5{margin-left:41.6666666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.3333333333%}.offset-md-8{margin-left:66.6666666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.3333333333%}.offset-md-11{margin-left:91.6666666667%}}@media(min-width:992px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex:0 0 auto;max-width:none;width:auto}.col-lg-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-lg-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-lg-3{flex:0 0 25%;max-width:25%}.col-lg-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-lg-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-lg-6{flex:0 0 50%;max-width:50%}.col-lg-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-lg-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-lg-9{flex:0 0 75%;max-width:75%}.col-lg-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-lg-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-lg-12{flex:0 0 100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.3333333333%}.offset-lg-2{margin-left:16.6666666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.3333333333%}.offset-lg-5{margin-left:41.6666666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.3333333333%}.offset-lg-8{margin-left:66.6666666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.3333333333%}.offset-lg-11{margin-left:91.6666666667%}}@media(min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex:0 0 auto;max-width:none;width:auto}.col-xl-1{flex:0 0 8.3333333333%;max-width:8.3333333333%}.col-xl-2{flex:0 0 16.6666666667%;max-width:16.6666666667%}.col-xl-3{flex:0 0 25%;max-width:25%}.col-xl-4{flex:0 0 33.3333333333%;max-width:33.3333333333%}.col-xl-5{flex:0 0 41.6666666667%;max-width:41.6666666667%}.col-xl-6{flex:0 0 50%;max-width:50%}.col-xl-7{flex:0 0 58.3333333333%;max-width:58.3333333333%}.col-xl-8{flex:0 0 66.6666666667%;max-width:66.6666666667%}.col-xl-9{flex:0 0 75%;max-width:75%}.col-xl-10{flex:0 0 83.3333333333%;max-width:83.3333333333%}.col-xl-11{flex:0 0 91.6666666667%;max-width:91.6666666667%}.col-xl-12{flex:0 0 100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.3333333333%}.offset-xl-2{margin-left:16.6666666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.3333333333%}.offset-xl-5{margin-left:41.6666666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.3333333333%}.offset-xl-8{margin-left:66.6666666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.3333333333%}.offset-xl-11{margin-left:91.6666666667%}}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}@media(min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}}@media(min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}}@media(min-width:992px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}}@media(min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}@media(min-width:576px){.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}}@media(min-width:768px){.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}}@media(min-width:992px){.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}}@media(min-width:1200px){.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}}.system-viewer{background:#f5f5f5;height:100vh;overflow:hidden;padding-top:61px}.system-viewer>div{max-width:100vw}.btn{cursor:pointer;display:inline-block}.btn:active{transform:translateY(-2px)}.delete-btn{background:#fff;border-radius:0 40px 40px 0;color:#c50000;font-family:system-ui;font-weight:300;opacity:0;padding:0 6px 2px;position:absolute;right:-4px;top:1px}.delete-btn:hover{opacity:1}.page-header{align-items:center;background:#fff;border-bottom:1px solid #9494b7;display:flex;height:62px;justify-content:center;padding:0 35px;position:absolute;top:0;width:100vw}.page-header__title{color:#6886ba;font-family:Malkor;font-size:28px;margin-right:10px;text-shadow:1px 1px 2px #d6cbca}.scroll-buffer{height:20vh}::-webkit-input-placeholder{font-style:italic}:-moz-placeholder,::-moz-placeholder{font-style:italic}:-ms-input-placeholder{font-style:italic}@keyframes bounce{to{transform:scale(1.2)}}
15
- /*# sourceMappingURL=main.3396e24d.css.map*/