@cqa-lib/cqa-ui 1.1.191 → 1.1.192
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/esm2020/lib/test-case-details/api-edit-step/api-edit-step.component.mjs +610 -11
- package/esm2020/lib/test-case-details/test-case-details-renderer/test-case-details-renderer.component.mjs +15 -2
- package/fesm2015/cqa-lib-cqa-ui.mjs +721 -129
- package/fesm2015/cqa-lib-cqa-ui.mjs.map +1 -1
- package/fesm2020/cqa-lib-cqa-ui.mjs +623 -11
- package/fesm2020/cqa-lib-cqa-ui.mjs.map +1 -1
- package/lib/test-case-details/api-edit-step/api-edit-step.component.d.ts +96 -8
- package/lib/test-case-details/test-case-details-renderer/test-case-details-renderer.component.d.ts +4 -1
- package/package.json +1 -1
- package/styles.css +1 -1
|
@@ -17483,7 +17483,20 @@ class TestCaseDetailsRendererComponent {
|
|
|
17483
17483
|
wire('descriptionChange', this.descriptionChange);
|
|
17484
17484
|
wire('reusableChange', this.reusableChange);
|
|
17485
17485
|
wire('openExternal', this.openExternal);
|
|
17486
|
-
wire('edit',
|
|
17486
|
+
wire('edit', {
|
|
17487
|
+
emit: (v) => {
|
|
17488
|
+
// If child component emits void or nothing, use current step and index
|
|
17489
|
+
// If child component already emits an object, merge it with step and index
|
|
17490
|
+
if (v != null && typeof v === 'object' && 'step' in v && 'index' in v) {
|
|
17491
|
+
// Already has step and index, emit as-is
|
|
17492
|
+
this.edit.emit(v);
|
|
17493
|
+
}
|
|
17494
|
+
else {
|
|
17495
|
+
// Emit with current step and index
|
|
17496
|
+
this.edit.emit({ step: this.step, index: this.index });
|
|
17497
|
+
}
|
|
17498
|
+
},
|
|
17499
|
+
});
|
|
17487
17500
|
wire('link', this.link);
|
|
17488
17501
|
wire('duplicate', this.duplicate);
|
|
17489
17502
|
wire('delete', this.delete);
|
|
@@ -19616,6 +19629,152 @@ const API_EDIT_STEP_LABELS = {
|
|
|
19616
19629
|
const METHODS_WITHOUT_BODY = ['GET', 'HEAD', 'DELETE'];
|
|
19617
19630
|
/** Auto-close pairs for payload JSON editor: opening char -> closing char. */
|
|
19618
19631
|
const PAYLOAD_AUTO_CLOSE_PAIRS = { '{': '}', '[': ']', '"': '"', "'": "'" };
|
|
19632
|
+
function isSingleQuote(ch) {
|
|
19633
|
+
return ch === "'" || ch === '\u2018' || ch === '\u2019';
|
|
19634
|
+
}
|
|
19635
|
+
function isDoubleQuote(ch) {
|
|
19636
|
+
return ch === '"' || ch === '\u201C' || ch === '\u201D';
|
|
19637
|
+
}
|
|
19638
|
+
function isClosingQuote(ch, openQuote) {
|
|
19639
|
+
if (isSingleQuote(openQuote))
|
|
19640
|
+
return isSingleQuote(ch);
|
|
19641
|
+
if (isDoubleQuote(openQuote))
|
|
19642
|
+
return isDoubleQuote(ch);
|
|
19643
|
+
return ch === openQuote;
|
|
19644
|
+
}
|
|
19645
|
+
/**
|
|
19646
|
+
* Tokenize a string respecting single- and double-quoted segments (for cURL args).
|
|
19647
|
+
* Handles straight and smart/curly quotes so pasted cURLs from browsers/docs work.
|
|
19648
|
+
*/
|
|
19649
|
+
function tokenizeCurlLine(line) {
|
|
19650
|
+
const tokens = [];
|
|
19651
|
+
let i = 0;
|
|
19652
|
+
const n = line.length;
|
|
19653
|
+
while (i < n) {
|
|
19654
|
+
while (i < n && /\s/.test(line[i]))
|
|
19655
|
+
i++;
|
|
19656
|
+
if (i >= n)
|
|
19657
|
+
break;
|
|
19658
|
+
const ch = line[i];
|
|
19659
|
+
if (isSingleQuote(ch) || isDoubleQuote(ch)) {
|
|
19660
|
+
const quote = ch;
|
|
19661
|
+
i++;
|
|
19662
|
+
let value = '';
|
|
19663
|
+
while (i < n && !isClosingQuote(line[i], quote)) {
|
|
19664
|
+
if (line[i] === '\\') {
|
|
19665
|
+
i++;
|
|
19666
|
+
if (i < n)
|
|
19667
|
+
value += line[i++];
|
|
19668
|
+
}
|
|
19669
|
+
else {
|
|
19670
|
+
value += line[i++];
|
|
19671
|
+
}
|
|
19672
|
+
}
|
|
19673
|
+
if (i < n)
|
|
19674
|
+
i++;
|
|
19675
|
+
tokens.push(value);
|
|
19676
|
+
continue;
|
|
19677
|
+
}
|
|
19678
|
+
let word = '';
|
|
19679
|
+
while (i < n && !/\s/.test(line[i]) && !isSingleQuote(line[i]) && !isDoubleQuote(line[i])) {
|
|
19680
|
+
word += line[i++];
|
|
19681
|
+
}
|
|
19682
|
+
if (word)
|
|
19683
|
+
tokens.push(word);
|
|
19684
|
+
}
|
|
19685
|
+
return tokens;
|
|
19686
|
+
}
|
|
19687
|
+
/** Strip one layer of surrounding single or double quotes from a string (e.g. '{"x":1}' -> {"x":1}). */
|
|
19688
|
+
function stripSurroundingQuotes(s) {
|
|
19689
|
+
if (s.length >= 2 && (s.startsWith("'") && s.endsWith("'")) || (s.startsWith('"') && s.endsWith('"'))) {
|
|
19690
|
+
return s.slice(1, -1);
|
|
19691
|
+
}
|
|
19692
|
+
return s;
|
|
19693
|
+
}
|
|
19694
|
+
/**
|
|
19695
|
+
* Parse a cURL command string and return method, url, headers, and body.
|
|
19696
|
+
* Supports -X/--request, -H/--header, -d/--data/--data-raw/--data-binary, and URL.
|
|
19697
|
+
* Handles line continuations (backslash-newline) and quoted body payloads.
|
|
19698
|
+
*/
|
|
19699
|
+
function parseCurl(curlString) {
|
|
19700
|
+
const raw = (curlString !== null && curlString !== void 0 ? curlString : '').trim();
|
|
19701
|
+
if (!raw)
|
|
19702
|
+
return null;
|
|
19703
|
+
// Remove line continuations (backslash followed by newline) so they don't break tokenization
|
|
19704
|
+
const noContinuations = raw.replace(/\\\s*\r?\n\s*/g, ' ');
|
|
19705
|
+
const normalized = noContinuations.replace(/\r?\n/g, ' ').replace(/\s+/g, ' ');
|
|
19706
|
+
const tokens = tokenizeCurlLine(normalized);
|
|
19707
|
+
let method = 'GET';
|
|
19708
|
+
let url = '';
|
|
19709
|
+
const headers = [];
|
|
19710
|
+
let body = '';
|
|
19711
|
+
const urlPattern = /^https?:\/\//i;
|
|
19712
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
19713
|
+
const t = tokens[i];
|
|
19714
|
+
const consumeNext = () => {
|
|
19715
|
+
i++;
|
|
19716
|
+
return tokens[i];
|
|
19717
|
+
};
|
|
19718
|
+
if (t === '-X' || t === '--request') {
|
|
19719
|
+
const value = consumeNext();
|
|
19720
|
+
if (value)
|
|
19721
|
+
method = value.toUpperCase();
|
|
19722
|
+
continue;
|
|
19723
|
+
}
|
|
19724
|
+
if (t === '-H' || t === '--header') {
|
|
19725
|
+
const value = consumeNext();
|
|
19726
|
+
if (value) {
|
|
19727
|
+
const colon = value.indexOf(':');
|
|
19728
|
+
if (colon !== -1) {
|
|
19729
|
+
const name = value.slice(0, colon).trim();
|
|
19730
|
+
const headerValue = value.slice(colon + 1).trim();
|
|
19731
|
+
if (name)
|
|
19732
|
+
headers.push({ name, type: 'string', value: headerValue });
|
|
19733
|
+
}
|
|
19734
|
+
}
|
|
19735
|
+
continue;
|
|
19736
|
+
}
|
|
19737
|
+
if (t === '-d' || t === '--data' || t === '--data-raw' || t === '--data-binary' || t === '--data-ascii') {
|
|
19738
|
+
const value = consumeNext();
|
|
19739
|
+
if (value != null && !String(value).startsWith('@'))
|
|
19740
|
+
body = stripSurroundingQuotes(value);
|
|
19741
|
+
continue;
|
|
19742
|
+
}
|
|
19743
|
+
if (t.startsWith('--data=')) {
|
|
19744
|
+
const value = t.slice(7);
|
|
19745
|
+
if (!value.startsWith('@'))
|
|
19746
|
+
body = stripSurroundingQuotes(value.replace(/^["']|["']$/g, ''));
|
|
19747
|
+
continue;
|
|
19748
|
+
}
|
|
19749
|
+
if (t.startsWith('--data-raw=')) {
|
|
19750
|
+
const value = t.slice(11);
|
|
19751
|
+
if (!value.startsWith('@'))
|
|
19752
|
+
body = stripSurroundingQuotes(value.replace(/^["']|["']$/g, ''));
|
|
19753
|
+
continue;
|
|
19754
|
+
}
|
|
19755
|
+
if (t.startsWith('-d')) {
|
|
19756
|
+
const value = t.length > 2 ? t.slice(2) : consumeNext();
|
|
19757
|
+
if (value != null && !value.startsWith('@'))
|
|
19758
|
+
body = stripSurroundingQuotes(value);
|
|
19759
|
+
continue;
|
|
19760
|
+
}
|
|
19761
|
+
if (urlPattern.test(t)) {
|
|
19762
|
+
if (!url)
|
|
19763
|
+
url = t;
|
|
19764
|
+
}
|
|
19765
|
+
}
|
|
19766
|
+
if (!url) {
|
|
19767
|
+
const firstUrl = tokens.find((tok) => urlPattern.test(tok));
|
|
19768
|
+
if (firstUrl)
|
|
19769
|
+
url = firstUrl;
|
|
19770
|
+
}
|
|
19771
|
+
// Many cURLs (e.g. from browser devtools) omit -X POST when sending a body; infer POST
|
|
19772
|
+
const finalMethod = (method || 'GET').toUpperCase();
|
|
19773
|
+
if (body && (finalMethod === 'GET' || finalMethod === 'HEAD')) {
|
|
19774
|
+
return { method: 'POST', url, headers, body };
|
|
19775
|
+
}
|
|
19776
|
+
return { method: finalMethod, url, headers, body };
|
|
19777
|
+
}
|
|
19619
19778
|
class ApiEditStepComponent {
|
|
19620
19779
|
constructor(fb, cdr) {
|
|
19621
19780
|
this.fb = fb;
|
|
@@ -19627,6 +19786,8 @@ class ApiEditStepComponent {
|
|
|
19627
19786
|
/** Emits when user clicks Send Request, with environment, method, url, and headers. */
|
|
19628
19787
|
this.sendRequest = new EventEmitter();
|
|
19629
19788
|
this.back = new EventEmitter();
|
|
19789
|
+
/** Emits when user clicks the Cancel button (step 1). */
|
|
19790
|
+
this.cancel = new EventEmitter();
|
|
19630
19791
|
this.next = new EventEmitter();
|
|
19631
19792
|
/** Emits when user clicks Create with all entered details: step1 (environment, HTTP method, URL, headers, body), step2 (variable name), step3 (verifications). */
|
|
19632
19793
|
this.create = new EventEmitter();
|
|
@@ -19664,16 +19825,41 @@ class ApiEditStepComponent {
|
|
|
19664
19825
|
searchable: false,
|
|
19665
19826
|
options: [],
|
|
19666
19827
|
};
|
|
19828
|
+
/** Auth type options: array of strings or objects with id, name, value, label (passed from parent). Falls back to built-in list when empty. */
|
|
19829
|
+
this.authTypeOptions = [];
|
|
19830
|
+
/** Config for Auth Type dropdown (updated when authTypeOptions changes, like environment) */
|
|
19831
|
+
this.authTypeSelectConfig = {
|
|
19832
|
+
key: 'authType',
|
|
19833
|
+
placeholder: 'No Auth',
|
|
19834
|
+
searchable: false,
|
|
19835
|
+
options: [],
|
|
19836
|
+
};
|
|
19837
|
+
/** Bearer token value (Authorization tab, when auth type is Bearer Token). */
|
|
19838
|
+
this.bearerToken = '';
|
|
19839
|
+
this.oauth2GrantTypeSelectConfig = {
|
|
19840
|
+
key: 'grantType',
|
|
19841
|
+
placeholder: 'Select grant type',
|
|
19842
|
+
searchable: false,
|
|
19843
|
+
options: [...ApiEditStepComponent.OAUTH_GRANT_TYPE_OPTIONS],
|
|
19844
|
+
};
|
|
19845
|
+
this.oauth2ClientAuthSelectConfig = {
|
|
19846
|
+
key: 'clientAuthentication',
|
|
19847
|
+
placeholder: 'Select method',
|
|
19848
|
+
searchable: false,
|
|
19849
|
+
options: [...ApiEditStepComponent.OAUTH_CLIENT_AUTH_OPTIONS],
|
|
19850
|
+
};
|
|
19667
19851
|
/** Cached environment value from last selection (so Create payload has the selected value). */
|
|
19668
19852
|
this.currentEnvironmentValue = '';
|
|
19669
19853
|
/** Cached HTTP method from last selection (so Create payload has the selected value). */
|
|
19670
19854
|
this.currentMethodValue = '';
|
|
19671
|
-
this.
|
|
19855
|
+
this._url = '';
|
|
19856
|
+
/** When true, params form changes should not update the URL (we're syncing from URL). */
|
|
19857
|
+
this.paramsSyncingFromUrl = false;
|
|
19672
19858
|
this.payloadTabs = [
|
|
19859
|
+
{ value: 'authorization', label: 'Authorization' },
|
|
19673
19860
|
{ value: 'headers', label: 'Headers' },
|
|
19674
19861
|
{ value: 'body', label: 'Body' },
|
|
19675
19862
|
{ value: 'params', label: 'Params' },
|
|
19676
|
-
{ value: 'scripts', label: 'Scripts' },
|
|
19677
19863
|
];
|
|
19678
19864
|
this.activePayloadTab = 'headers';
|
|
19679
19865
|
/** Step 3: Response verification tabs */
|
|
@@ -19682,7 +19868,7 @@ class ApiEditStepComponent {
|
|
|
19682
19868
|
{ value: 'status', label: 'Status' },
|
|
19683
19869
|
];
|
|
19684
19870
|
this.activeResponseVerificationTab = 'response-body';
|
|
19685
|
-
/** Payload type for Body/Params/
|
|
19871
|
+
/** Payload type for Body/Params/Authorization: raw, x-www-form-urlencoded, form-data */
|
|
19686
19872
|
this.payloadType = 'raw';
|
|
19687
19873
|
/** Segment options for payload type (used by cqa-segment-control) */
|
|
19688
19874
|
this.payloadTypeSegments = [
|
|
@@ -19699,7 +19885,7 @@ class ApiEditStepComponent {
|
|
|
19699
19885
|
searchable: false,
|
|
19700
19886
|
options: [...ApiEditStepComponent.DEFAULT_FORMAT_OPTIONS],
|
|
19701
19887
|
};
|
|
19702
|
-
/** Payload text area value for Body/Params/
|
|
19888
|
+
/** Payload text area value for Body/Params/Authorization */
|
|
19703
19889
|
this.payloadText = '';
|
|
19704
19890
|
/** JSON parse error when format is JSON and payload is invalid; null when valid or not JSON. */
|
|
19705
19891
|
this.payloadJsonError = null;
|
|
@@ -19797,16 +19983,16 @@ class ApiEditStepComponent {
|
|
|
19797
19983
|
.filter((v) => v != null);
|
|
19798
19984
|
}
|
|
19799
19985
|
static toSelectOption(item) {
|
|
19800
|
-
var _a,
|
|
19986
|
+
var _a, _c, _d, _e, _f, _g, _h, _j;
|
|
19801
19987
|
if (typeof item === 'string') {
|
|
19802
19988
|
return { id: item, value: item, name: item, label: item };
|
|
19803
19989
|
}
|
|
19804
19990
|
const o = item;
|
|
19805
19991
|
return {
|
|
19806
19992
|
id: (_a = o.id) !== null && _a !== void 0 ? _a : o.value,
|
|
19807
|
-
value: (
|
|
19808
|
-
name: (
|
|
19809
|
-
label: (
|
|
19993
|
+
value: (_c = o.value) !== null && _c !== void 0 ? _c : o.id,
|
|
19994
|
+
name: (_e = (_d = o.name) !== null && _d !== void 0 ? _d : o.label) !== null && _e !== void 0 ? _e : String((_f = o.value) !== null && _f !== void 0 ? _f : o.id),
|
|
19995
|
+
label: (_h = (_g = o.label) !== null && _g !== void 0 ? _g : o.name) !== null && _h !== void 0 ? _h : String((_j = o.value) !== null && _j !== void 0 ? _j : o.id),
|
|
19810
19996
|
};
|
|
19811
19997
|
}
|
|
19812
19998
|
static getOptionValue(item) {
|
|
@@ -19828,15 +20014,39 @@ class ApiEditStepComponent {
|
|
|
19828
20014
|
.map((e) => ApiEditStepComponent.getOptionValue(e))
|
|
19829
20015
|
.filter((v) => v != null);
|
|
19830
20016
|
}
|
|
20017
|
+
updateAuthTypeSelectConfig() {
|
|
20018
|
+
var _a;
|
|
20019
|
+
const options = ((_a = this.authTypeOptions) === null || _a === void 0 ? void 0 : _a.length) > 0
|
|
20020
|
+
? this.authTypeOptions.map((a) => ApiEditStepComponent.toSelectOption(a))
|
|
20021
|
+
: [...ApiEditStepComponent.DEFAULT_AUTH_TYPE_OPTIONS];
|
|
20022
|
+
this.authTypeSelectConfig = Object.assign(Object.assign({}, this.authTypeSelectConfig), { options });
|
|
20023
|
+
}
|
|
20024
|
+
getAuthTypeValues() {
|
|
20025
|
+
var _a;
|
|
20026
|
+
const source = ((_a = this.authTypeOptions) === null || _a === void 0 ? void 0 : _a.length) > 0
|
|
20027
|
+
? this.authTypeOptions
|
|
20028
|
+
: ApiEditStepComponent.DEFAULT_AUTH_TYPE_OPTIONS;
|
|
20029
|
+
return source
|
|
20030
|
+
.map((a) => ApiEditStepComponent.getOptionValue(a))
|
|
20031
|
+
.filter((v) => v != null);
|
|
20032
|
+
}
|
|
20033
|
+
/** Current auth type value (e.g. 'no-auth') for template */
|
|
20034
|
+
get selectedAuthType() {
|
|
20035
|
+
var _a, _c, _d, _e;
|
|
20036
|
+
const v = (_c = (_a = this.authTypeForm) === null || _a === void 0 ? void 0 : _a.get('authType')) === null || _c === void 0 ? void 0 : _c.value;
|
|
20037
|
+
if (v == null || v === '')
|
|
20038
|
+
return 'no-auth';
|
|
20039
|
+
return typeof v === 'object' ? ((_e = (_d = v === null || v === void 0 ? void 0 : v.value) !== null && _d !== void 0 ? _d : v === null || v === void 0 ? void 0 : v.id) !== null && _e !== void 0 ? _e : 'no-auth') : String(v);
|
|
20040
|
+
}
|
|
19831
20041
|
/** Current HTTP method (from form or default: first of httpMethodOptions). Treats empty string as unset. */
|
|
19832
20042
|
get selectedMethod() {
|
|
19833
|
-
var _a,
|
|
19834
|
-
const value = (
|
|
19835
|
-
const firstValue = ((
|
|
20043
|
+
var _a, _c, _d, _e;
|
|
20044
|
+
const value = (_c = (_a = this.methodForm) === null || _a === void 0 ? void 0 : _a.get('method')) === null || _c === void 0 ? void 0 : _c.value;
|
|
20045
|
+
const firstValue = ((_d = this.httpMethodOptions) === null || _d === void 0 ? void 0 : _d.length)
|
|
19836
20046
|
? ApiEditStepComponent.getOptionValue(this.httpMethodOptions[0])
|
|
19837
20047
|
: undefined;
|
|
19838
20048
|
const resolved = value != null && value !== '' ? (typeof value === 'object' ? ApiEditStepComponent.getOptionValue(value) : String(value)) : undefined;
|
|
19839
|
-
return (
|
|
20049
|
+
return (_e = resolved !== null && resolved !== void 0 ? resolved : firstValue) !== null && _e !== void 0 ? _e : 'GET';
|
|
19840
20050
|
}
|
|
19841
20051
|
set selectedMethod(v) {
|
|
19842
20052
|
var _a;
|
|
@@ -19849,13 +20059,13 @@ class ApiEditStepComponent {
|
|
|
19849
20059
|
}
|
|
19850
20060
|
/** Current environment (from form or default: first of environmentOptions). Treats empty string as unset. */
|
|
19851
20061
|
get selectedEnvironment() {
|
|
19852
|
-
var _a,
|
|
19853
|
-
const value = (
|
|
19854
|
-
const firstValue = ((
|
|
20062
|
+
var _a, _c, _d, _e;
|
|
20063
|
+
const value = (_c = (_a = this.environmentForm) === null || _a === void 0 ? void 0 : _a.get('environment')) === null || _c === void 0 ? void 0 : _c.value;
|
|
20064
|
+
const firstValue = ((_d = this.environmentOptions) === null || _d === void 0 ? void 0 : _d.length)
|
|
19855
20065
|
? ApiEditStepComponent.getOptionValue(this.environmentOptions[0])
|
|
19856
20066
|
: undefined;
|
|
19857
20067
|
const resolved = value != null && value !== '' ? (typeof value === 'object' ? ApiEditStepComponent.getOptionValue(value) : String(value)) : undefined;
|
|
19858
|
-
return (
|
|
20068
|
+
return (_e = resolved !== null && resolved !== void 0 ? resolved : firstValue) !== null && _e !== void 0 ? _e : 'Development';
|
|
19859
20069
|
}
|
|
19860
20070
|
set selectedEnvironment(v) {
|
|
19861
20071
|
var _a;
|
|
@@ -19883,6 +20093,21 @@ class ApiEditStepComponent {
|
|
|
19883
20093
|
: String(v)
|
|
19884
20094
|
: '';
|
|
19885
20095
|
}
|
|
20096
|
+
/** URL for the request. Getter/setter syncs query params with the Params tab (Postman-style). */
|
|
20097
|
+
get url() {
|
|
20098
|
+
return this._url;
|
|
20099
|
+
}
|
|
20100
|
+
set url(value) {
|
|
20101
|
+
const next = value !== null && value !== void 0 ? value : '';
|
|
20102
|
+
if (this._url === next)
|
|
20103
|
+
return;
|
|
20104
|
+
this._url = next;
|
|
20105
|
+
if (this.paramsFormArray) {
|
|
20106
|
+
this.paramsSyncingFromUrl = true;
|
|
20107
|
+
this.syncParamsFromUrl();
|
|
20108
|
+
this.paramsSyncingFromUrl = false;
|
|
20109
|
+
}
|
|
20110
|
+
}
|
|
19886
20111
|
onPayloadTypeChange(val) {
|
|
19887
20112
|
this.payloadType = val;
|
|
19888
20113
|
}
|
|
@@ -19909,8 +20134,8 @@ class ApiEditStepComponent {
|
|
|
19909
20134
|
}
|
|
19910
20135
|
/** Whether current payload format is JSON (so we validate and show JSON editor behavior). */
|
|
19911
20136
|
get isPayloadFormatJson() {
|
|
19912
|
-
var _a,
|
|
19913
|
-
const format = (
|
|
20137
|
+
var _a, _c;
|
|
20138
|
+
const format = (_c = (_a = this.payloadFormatForm) === null || _a === void 0 ? void 0 : _a.get('format')) === null || _c === void 0 ? void 0 : _c.value;
|
|
19914
20139
|
return format === 'json';
|
|
19915
20140
|
}
|
|
19916
20141
|
/** Error messages for the payload textarea (red border + bottom line). */
|
|
@@ -19935,7 +20160,7 @@ class ApiEditStepComponent {
|
|
|
19935
20160
|
this.onPayloadTextChange((_a = target === null || target === void 0 ? void 0 : target.value) !== null && _a !== void 0 ? _a : '');
|
|
19936
20161
|
}
|
|
19937
20162
|
onPayloadKeydown(event) {
|
|
19938
|
-
var _a,
|
|
20163
|
+
var _a, _c;
|
|
19939
20164
|
if (!this.isPayloadFormatJson)
|
|
19940
20165
|
return;
|
|
19941
20166
|
const key = event.key;
|
|
@@ -19947,7 +20172,7 @@ class ApiEditStepComponent {
|
|
|
19947
20172
|
return;
|
|
19948
20173
|
event.preventDefault();
|
|
19949
20174
|
const start = (_a = target.selectionStart) !== null && _a !== void 0 ? _a : 0;
|
|
19950
|
-
const end = (
|
|
20175
|
+
const end = (_c = target.selectionEnd) !== null && _c !== void 0 ? _c : start;
|
|
19951
20176
|
const before = this.payloadText.slice(0, start);
|
|
19952
20177
|
const after = this.payloadText.slice(end);
|
|
19953
20178
|
const insertPos = start + 1;
|
|
@@ -19955,13 +20180,13 @@ class ApiEditStepComponent {
|
|
|
19955
20180
|
this.payloadText = newValue;
|
|
19956
20181
|
this.validatePayloadJson();
|
|
19957
20182
|
setTimeout(() => {
|
|
19958
|
-
var _a,
|
|
19959
|
-
(
|
|
20183
|
+
var _a, _c;
|
|
20184
|
+
(_c = (_a = this.payloadTextareaRef) === null || _a === void 0 ? void 0 : _a.nativeElement) === null || _c === void 0 ? void 0 : _c.setSelectionRange(insertPos, insertPos);
|
|
19960
20185
|
}, 0);
|
|
19961
20186
|
}
|
|
19962
20187
|
/** Validate payload when format is JSON; sets payloadJsonError or clears it. */
|
|
19963
20188
|
validatePayloadJson() {
|
|
19964
|
-
var _a,
|
|
20189
|
+
var _a, _c;
|
|
19965
20190
|
if (!this.isPayloadFormatJson) {
|
|
19966
20191
|
this.payloadJsonError = null;
|
|
19967
20192
|
return;
|
|
@@ -19981,7 +20206,7 @@ class ApiEditStepComponent {
|
|
|
19981
20206
|
const { line, column } = this.positionToLineColumn(text, position);
|
|
19982
20207
|
const lines = text.split(/\r?\n/);
|
|
19983
20208
|
const lineIndex = Math.max(0, line - 1);
|
|
19984
|
-
const lineContent = (
|
|
20209
|
+
const lineContent = (_c = lines[lineIndex]) !== null && _c !== void 0 ? _c : '';
|
|
19985
20210
|
const excerpt = lineContent || ' ';
|
|
19986
20211
|
const caretOffset = lineIndex === line - 1 ? Math.min(column - 1, lineContent.length) : 0;
|
|
19987
20212
|
this.payloadJsonError = {
|
|
@@ -20016,8 +20241,8 @@ class ApiEditStepComponent {
|
|
|
20016
20241
|
}
|
|
20017
20242
|
/** Typed accessor for template (FormArray.controls is AbstractControl[]) */
|
|
20018
20243
|
get headerRows() {
|
|
20019
|
-
var _a,
|
|
20020
|
-
return ((
|
|
20244
|
+
var _a, _c;
|
|
20245
|
+
return ((_c = (_a = this.headersFormArray) === null || _a === void 0 ? void 0 : _a.controls) !== null && _c !== void 0 ? _c : []);
|
|
20021
20246
|
}
|
|
20022
20247
|
updateHeaderNameSelectConfig() {
|
|
20023
20248
|
var _a;
|
|
@@ -20025,7 +20250,7 @@ class ApiEditStepComponent {
|
|
|
20025
20250
|
? this.headerNameOptions
|
|
20026
20251
|
: ApiEditStepComponent.DEFAULT_HEADER_NAME_OPTIONS;
|
|
20027
20252
|
const baseOptions = source.map((h) => ApiEditStepComponent.toSelectOption(h));
|
|
20028
|
-
const baseValues = new Set(baseOptions.map((o) => { var _a,
|
|
20253
|
+
const baseValues = new Set(baseOptions.map((o) => { var _a, _c; return String((_c = (_a = o.value) !== null && _a !== void 0 ? _a : o.id) !== null && _c !== void 0 ? _c : '').trim(); }).filter(Boolean));
|
|
20029
20254
|
const currentNamesFromForm = this.getCurrentHeaderNamesFromForm();
|
|
20030
20255
|
const extraOptions = [];
|
|
20031
20256
|
for (const name of currentNamesFromForm) {
|
|
@@ -20040,13 +20265,13 @@ class ApiEditStepComponent {
|
|
|
20040
20265
|
}
|
|
20041
20266
|
/** Collects distinct non-empty header names currently in the headers form (for dynamic options). */
|
|
20042
20267
|
getCurrentHeaderNamesFromForm() {
|
|
20043
|
-
var _a,
|
|
20268
|
+
var _a, _c, _d;
|
|
20044
20269
|
const names = [];
|
|
20045
20270
|
const seen = new Set();
|
|
20046
|
-
if (!((
|
|
20271
|
+
if (!((_c = (_a = this.headersFormArray) === null || _a === void 0 ? void 0 : _a.controls) === null || _c === void 0 ? void 0 : _c.length))
|
|
20047
20272
|
return names;
|
|
20048
20273
|
for (const control of this.headersFormArray.controls) {
|
|
20049
|
-
const name = (
|
|
20274
|
+
const name = (_d = control.get('name')) === null || _d === void 0 ? void 0 : _d.value;
|
|
20050
20275
|
const str = name != null ? String(name).trim() : '';
|
|
20051
20276
|
if (str && !seen.has(str)) {
|
|
20052
20277
|
seen.add(str);
|
|
@@ -20056,16 +20281,20 @@ class ApiEditStepComponent {
|
|
|
20056
20281
|
return names;
|
|
20057
20282
|
}
|
|
20058
20283
|
get keyValueRows() {
|
|
20059
|
-
var _a,
|
|
20060
|
-
return ((
|
|
20284
|
+
var _a, _c;
|
|
20285
|
+
return ((_c = (_a = this.keyValueFormArray) === null || _a === void 0 ? void 0 : _a.controls) !== null && _c !== void 0 ? _c : []);
|
|
20061
20286
|
}
|
|
20062
20287
|
get keyTypeValueRows() {
|
|
20063
|
-
var _a,
|
|
20064
|
-
return ((
|
|
20288
|
+
var _a, _c;
|
|
20289
|
+
return ((_c = (_a = this.keyTypeValueFormArray) === null || _a === void 0 ? void 0 : _a.controls) !== null && _c !== void 0 ? _c : []);
|
|
20290
|
+
}
|
|
20291
|
+
get paramsRows() {
|
|
20292
|
+
var _a, _c;
|
|
20293
|
+
return ((_c = (_a = this.paramsFormArray) === null || _a === void 0 ? void 0 : _a.controls) !== null && _c !== void 0 ? _c : []);
|
|
20065
20294
|
}
|
|
20066
20295
|
get verificationRows() {
|
|
20067
|
-
var _a,
|
|
20068
|
-
return ((
|
|
20296
|
+
var _a, _c;
|
|
20297
|
+
return ((_c = (_a = this.verificationFormArray) === null || _a === void 0 ? void 0 : _a.controls) !== null && _c !== void 0 ? _c : []);
|
|
20069
20298
|
}
|
|
20070
20299
|
updateVerificationSelectConfig() {
|
|
20071
20300
|
var _a;
|
|
@@ -20108,8 +20337,8 @@ class ApiEditStepComponent {
|
|
|
20108
20337
|
return values.length > 0 ? values[0] : 'string';
|
|
20109
20338
|
}
|
|
20110
20339
|
get statusVerificationRows() {
|
|
20111
|
-
var _a,
|
|
20112
|
-
return ((
|
|
20340
|
+
var _a, _c;
|
|
20341
|
+
return ((_c = (_a = this.statusVerificationFormArray) === null || _a === void 0 ? void 0 : _a.controls) !== null && _c !== void 0 ? _c : []);
|
|
20113
20342
|
}
|
|
20114
20343
|
updateStatusVerificationSelectConfig() {
|
|
20115
20344
|
var _a;
|
|
@@ -20132,36 +20361,50 @@ class ApiEditStepComponent {
|
|
|
20132
20361
|
return values.length > 0 ? values[0] : 'equals';
|
|
20133
20362
|
}
|
|
20134
20363
|
ngOnInit() {
|
|
20135
|
-
var _a,
|
|
20364
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
|
|
20136
20365
|
this.applyInitialStep(this.initialStep);
|
|
20137
20366
|
this.updateMethodSelectConfig();
|
|
20138
20367
|
this.updateHeaderNameSelectConfig();
|
|
20139
20368
|
const firstMethodValue = ((_a = this.httpMethodOptions) === null || _a === void 0 ? void 0 : _a.length)
|
|
20140
20369
|
? ApiEditStepComponent.getOptionValue(this.httpMethodOptions[0])
|
|
20141
20370
|
: undefined;
|
|
20142
|
-
const defaultMethod = (
|
|
20143
|
-
this.currentMethodValue = typeof defaultMethod === 'string' ? defaultMethod : ((
|
|
20371
|
+
const defaultMethod = (_d = (_c = this.initialMethod) !== null && _c !== void 0 ? _c : firstMethodValue) !== null && _d !== void 0 ? _d : 'GET';
|
|
20372
|
+
this.currentMethodValue = typeof defaultMethod === 'string' ? defaultMethod : ((_e = ApiEditStepComponent.getOptionValue(defaultMethod)) !== null && _e !== void 0 ? _e : '');
|
|
20144
20373
|
this.methodForm = this.fb.group({
|
|
20145
20374
|
method: [defaultMethod],
|
|
20146
20375
|
});
|
|
20147
|
-
const firstValue = ((
|
|
20376
|
+
const firstValue = ((_f = this.environmentOptions) === null || _f === void 0 ? void 0 : _f.length)
|
|
20148
20377
|
? ApiEditStepComponent.getOptionValue(this.environmentOptions[0])
|
|
20149
20378
|
: undefined;
|
|
20150
|
-
const defaultEnv = (
|
|
20151
|
-
this.currentEnvironmentValue = typeof defaultEnv === 'string' ? defaultEnv : ((
|
|
20379
|
+
const defaultEnv = (_h = (_g = this.initialEnvironment) !== null && _g !== void 0 ? _g : firstValue) !== null && _h !== void 0 ? _h : 'Development';
|
|
20380
|
+
this.currentEnvironmentValue = typeof defaultEnv === 'string' ? defaultEnv : ((_j = ApiEditStepComponent.getOptionValue(defaultEnv)) !== null && _j !== void 0 ? _j : '');
|
|
20152
20381
|
this.environmentForm = this.fb.group({
|
|
20153
20382
|
environment: [defaultEnv],
|
|
20154
20383
|
});
|
|
20155
|
-
this.
|
|
20384
|
+
this.updateAuthTypeSelectConfig();
|
|
20385
|
+
const firstAuthValue = this.getAuthTypeValues()[0];
|
|
20386
|
+
const defaultAuthType = (_l = (_k = this.initialAuthType) !== null && _k !== void 0 ? _k : firstAuthValue) !== null && _l !== void 0 ? _l : 'no-auth';
|
|
20387
|
+
this.authTypeForm = this.fb.group({
|
|
20388
|
+
authType: [defaultAuthType],
|
|
20389
|
+
});
|
|
20390
|
+
this.oauth2Form = this.fb.group({
|
|
20391
|
+
grantType: ['client_credentials'],
|
|
20392
|
+
accessTokenUrl: [''],
|
|
20393
|
+
clientId: [''],
|
|
20394
|
+
clientSecret: [''],
|
|
20395
|
+
scope: [''],
|
|
20396
|
+
clientAuthentication: ['basic'],
|
|
20397
|
+
});
|
|
20398
|
+
this.environmentFormChangesSub = (_o = (_m = this.environmentForm.get('environment')) === null || _m === void 0 ? void 0 : _m.valueChanges) === null || _o === void 0 ? void 0 : _o.subscribe((v) => {
|
|
20156
20399
|
const s = v != null && v !== '' ? (typeof v === 'object' ? ApiEditStepComponent.getOptionValue(v) : String(v)) : '';
|
|
20157
20400
|
this.currentEnvironmentValue = s !== null && s !== void 0 ? s : '';
|
|
20158
20401
|
});
|
|
20159
|
-
this.methodFormChangesSub = (
|
|
20402
|
+
this.methodFormChangesSub = (_q = (_p = this.methodForm.get('method')) === null || _p === void 0 ? void 0 : _p.valueChanges) === null || _q === void 0 ? void 0 : _q.subscribe((v) => {
|
|
20160
20403
|
const s = v != null && v !== '' ? (typeof v === 'object' ? ApiEditStepComponent.getOptionValue(v) : String(v)) : '';
|
|
20161
20404
|
this.currentMethodValue = s !== null && s !== void 0 ? s : '';
|
|
20162
20405
|
});
|
|
20163
|
-
this.buildHeadersFormArray((
|
|
20164
|
-
this.headerNameOptionsChangesSub = (
|
|
20406
|
+
this.buildHeadersFormArray((_r = this.initialHeaders) !== null && _r !== void 0 ? _r : [{ name: '', type: 'string', value: '' }]);
|
|
20407
|
+
this.headerNameOptionsChangesSub = (_t = (_s = this.headersFormArray) === null || _s === void 0 ? void 0 : _s.valueChanges) === null || _t === void 0 ? void 0 : _t.subscribe(() => {
|
|
20165
20408
|
this.updateHeaderNameSelectConfig();
|
|
20166
20409
|
this.headersChange.emit(this.headers);
|
|
20167
20410
|
});
|
|
@@ -20170,23 +20413,33 @@ class ApiEditStepComponent {
|
|
|
20170
20413
|
this.updateEnvironmentSelectConfig();
|
|
20171
20414
|
this.updatePayloadFormatSelectConfig();
|
|
20172
20415
|
const firstFormatValue = this.getFormatValues()[0];
|
|
20173
|
-
const defaultFormat = (
|
|
20416
|
+
const defaultFormat = (_v = (_u = this.initialFormat) !== null && _u !== void 0 ? _u : firstFormatValue) !== null && _v !== void 0 ? _v : 'json';
|
|
20174
20417
|
this.payloadFormatForm = this.fb.group({ format: [defaultFormat] });
|
|
20175
20418
|
this.buildKeyValueFormArray();
|
|
20176
20419
|
this.buildKeyTypeValueFormArray();
|
|
20420
|
+
this.buildParamsFormArray();
|
|
20421
|
+
this.paramsFormArrayChangesSub = (_w = this.paramsFormArray.valueChanges) === null || _w === void 0 ? void 0 : _w.subscribe(() => this.syncUrlFromParams());
|
|
20422
|
+
if (this.initialUrl != null && this.initialUrl !== '') {
|
|
20423
|
+
this._url = this.initialUrl;
|
|
20424
|
+
this.syncParamsFromUrl();
|
|
20425
|
+
}
|
|
20426
|
+
// Initialize variableName from initialVariableName
|
|
20427
|
+
if (this.initialVariableName != null && this.initialVariableName !== '') {
|
|
20428
|
+
this.variableName = this.initialVariableName;
|
|
20429
|
+
}
|
|
20177
20430
|
this.updateVerificationSelectConfig();
|
|
20178
20431
|
this.updateVerificationDataTypeSelectConfig();
|
|
20179
20432
|
this.buildVerificationFormArray();
|
|
20180
20433
|
this.updateStatusVerificationSelectConfig();
|
|
20181
20434
|
this.buildStatusVerificationFormArray();
|
|
20182
|
-
this.methodChangesSub = (
|
|
20435
|
+
this.methodChangesSub = (_y = (_x = this.methodForm.get('method')) === null || _x === void 0 ? void 0 : _x.valueChanges) === null || _y === void 0 ? void 0 : _y.subscribe((value) => {
|
|
20183
20436
|
const method = value != null ? String(value).toUpperCase() : '';
|
|
20184
20437
|
if (METHODS_WITHOUT_BODY.includes(method) && this.activePayloadTab !== 'headers') {
|
|
20185
20438
|
this.activePayloadTab = 'headers';
|
|
20186
20439
|
this.cdr.detectChanges();
|
|
20187
20440
|
}
|
|
20188
20441
|
});
|
|
20189
|
-
this.formatChangesSub = (
|
|
20442
|
+
this.formatChangesSub = (_0 = (_z = this.payloadFormatForm.get('format')) === null || _z === void 0 ? void 0 : _z.valueChanges) === null || _0 === void 0 ? void 0 : _0.subscribe(() => {
|
|
20190
20443
|
this.validatePayloadJson();
|
|
20191
20444
|
});
|
|
20192
20445
|
this.validatePayloadJson();
|
|
@@ -20195,12 +20448,13 @@ class ApiEditStepComponent {
|
|
|
20195
20448
|
this.setupPayloadTextareaScrollSync();
|
|
20196
20449
|
}
|
|
20197
20450
|
ngOnDestroy() {
|
|
20198
|
-
var _a,
|
|
20451
|
+
var _a, _c, _d, _e, _f, _g;
|
|
20199
20452
|
(_a = this.methodChangesSub) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
20200
|
-
(
|
|
20201
|
-
(
|
|
20202
|
-
(
|
|
20203
|
-
(
|
|
20453
|
+
(_c = this.formatChangesSub) === null || _c === void 0 ? void 0 : _c.unsubscribe();
|
|
20454
|
+
(_d = this.headerNameOptionsChangesSub) === null || _d === void 0 ? void 0 : _d.unsubscribe();
|
|
20455
|
+
(_e = this.environmentFormChangesSub) === null || _e === void 0 ? void 0 : _e.unsubscribe();
|
|
20456
|
+
(_f = this.methodFormChangesSub) === null || _f === void 0 ? void 0 : _f.unsubscribe();
|
|
20457
|
+
(_g = this.paramsFormArrayChangesSub) === null || _g === void 0 ? void 0 : _g.unsubscribe();
|
|
20204
20458
|
}
|
|
20205
20459
|
/** Sync line numbers column scroll with payload textarea scroll (Postman-style). */
|
|
20206
20460
|
setupPayloadTextareaScrollSync() {
|
|
@@ -20216,6 +20470,9 @@ class ApiEditStepComponent {
|
|
|
20216
20470
|
textarea.addEventListener('scroll', () => {
|
|
20217
20471
|
lineNumbersEl.scrollTop = textarea.scrollTop;
|
|
20218
20472
|
});
|
|
20473
|
+
lineNumbersEl.addEventListener('scroll', () => {
|
|
20474
|
+
textarea.scrollTop = lineNumbersEl.scrollTop;
|
|
20475
|
+
});
|
|
20219
20476
|
}, 0);
|
|
20220
20477
|
}
|
|
20221
20478
|
buildKeyValueFormArray(rows) {
|
|
@@ -20228,6 +20485,111 @@ class ApiEditStepComponent {
|
|
|
20228
20485
|
const groups = initial.map((r) => this.fb.group({ key: [r.key], type: [r.type], value: [r.value] }));
|
|
20229
20486
|
this.keyTypeValueFormArray = this.fb.array(groups);
|
|
20230
20487
|
}
|
|
20488
|
+
buildParamsFormArray(rows) {
|
|
20489
|
+
const initial = rows !== null && rows !== void 0 ? rows : [{ key: '', value: '' }];
|
|
20490
|
+
const groups = initial.map((r) => this.fb.group({ key: [r.key], value: [r.value] }));
|
|
20491
|
+
if (this.paramsFormArray) {
|
|
20492
|
+
this.paramsFormArray.clear();
|
|
20493
|
+
groups.forEach((g) => this.paramsFormArray.push(g));
|
|
20494
|
+
}
|
|
20495
|
+
else {
|
|
20496
|
+
this.paramsFormArray = this.fb.array(groups);
|
|
20497
|
+
}
|
|
20498
|
+
}
|
|
20499
|
+
/** Parse URL into base (without query/fragment) and query key-value pairs. Preserves relative URLs. */
|
|
20500
|
+
parseQueryParamsFromUrl(urlStr) {
|
|
20501
|
+
const empty = { baseUrl: urlStr, rows: [{ key: '', value: '' }] };
|
|
20502
|
+
if (!urlStr || !urlStr.trim())
|
|
20503
|
+
return empty;
|
|
20504
|
+
try {
|
|
20505
|
+
const isAbsolute = /^https?:\/\//i.test(urlStr.trim());
|
|
20506
|
+
const url = new URL(urlStr, 'http://localhost');
|
|
20507
|
+
const baseUrl = isAbsolute ? url.origin + url.pathname : url.pathname;
|
|
20508
|
+
const rows = [];
|
|
20509
|
+
url.searchParams.forEach((value, key) => {
|
|
20510
|
+
rows.push({ key, value });
|
|
20511
|
+
});
|
|
20512
|
+
if (rows.length === 0)
|
|
20513
|
+
rows.push({ key: '', value: '' });
|
|
20514
|
+
return { baseUrl, rows };
|
|
20515
|
+
}
|
|
20516
|
+
catch (_a) {
|
|
20517
|
+
return empty;
|
|
20518
|
+
}
|
|
20519
|
+
}
|
|
20520
|
+
/** Get base URL (without query/fragment) for building URL from params. Preserves relative URLs. */
|
|
20521
|
+
getBaseUrl(urlStr) {
|
|
20522
|
+
if (!urlStr || !urlStr.trim())
|
|
20523
|
+
return urlStr;
|
|
20524
|
+
try {
|
|
20525
|
+
const isAbsolute = /^https?:\/\//i.test(urlStr.trim());
|
|
20526
|
+
const url = new URL(urlStr, 'http://localhost');
|
|
20527
|
+
return isAbsolute ? url.origin + url.pathname : url.pathname;
|
|
20528
|
+
}
|
|
20529
|
+
catch (_a) {
|
|
20530
|
+
return urlStr;
|
|
20531
|
+
}
|
|
20532
|
+
}
|
|
20533
|
+
/** Parse application/x-www-form-urlencoded body (key=value&...) into key-value rows. */
|
|
20534
|
+
parseFormUrlEncodedBody(body) {
|
|
20535
|
+
const trimmed = (body !== null && body !== void 0 ? body : '').trim();
|
|
20536
|
+
if (!trimmed)
|
|
20537
|
+
return [];
|
|
20538
|
+
try {
|
|
20539
|
+
const params = new URLSearchParams(trimmed);
|
|
20540
|
+
const rows = [];
|
|
20541
|
+
params.forEach((value, key) => rows.push({ key, value }));
|
|
20542
|
+
return rows;
|
|
20543
|
+
}
|
|
20544
|
+
catch (_a) {
|
|
20545
|
+
return [];
|
|
20546
|
+
}
|
|
20547
|
+
}
|
|
20548
|
+
/**
|
|
20549
|
+
* If form body has a single key whose value is URL-decoded JSON, return it pretty-printed for Raw body.
|
|
20550
|
+
* Otherwise return null (caller keeps x-www-form-urlencoded view).
|
|
20551
|
+
*/
|
|
20552
|
+
tryFormBodyValueAsRawJson(rows) {
|
|
20553
|
+
var _a;
|
|
20554
|
+
if (rows.length !== 1 || !((_a = rows[0].value) === null || _a === void 0 ? void 0 : _a.trim()))
|
|
20555
|
+
return null;
|
|
20556
|
+
const value = rows[0].value.trim();
|
|
20557
|
+
if (!(value.startsWith('{') || value.startsWith('[')))
|
|
20558
|
+
return null;
|
|
20559
|
+
try {
|
|
20560
|
+
const parsed = JSON.parse(value);
|
|
20561
|
+
return JSON.stringify(parsed, null, 2);
|
|
20562
|
+
}
|
|
20563
|
+
catch (_c) {
|
|
20564
|
+
return null;
|
|
20565
|
+
}
|
|
20566
|
+
}
|
|
20567
|
+
/** Update Params table from current URL query string (Postman-style). */
|
|
20568
|
+
syncParamsFromUrl() {
|
|
20569
|
+
const { baseUrl: _b, rows } = this.parseQueryParamsFromUrl(this._url);
|
|
20570
|
+
this.buildParamsFormArray(rows);
|
|
20571
|
+
this.cdr.markForCheck();
|
|
20572
|
+
}
|
|
20573
|
+
/** Update URL query string from Params table (Postman-style). */
|
|
20574
|
+
syncUrlFromParams() {
|
|
20575
|
+
var _a, _c, _d, _e;
|
|
20576
|
+
if (this.paramsSyncingFromUrl || !this.paramsFormArray)
|
|
20577
|
+
return;
|
|
20578
|
+
const baseUrl = this.getBaseUrl(this._url);
|
|
20579
|
+
const params = new URLSearchParams();
|
|
20580
|
+
for (const c of this.paramsFormArray.controls) {
|
|
20581
|
+
const key = ((_c = (_a = c.get('key')) === null || _a === void 0 ? void 0 : _a.value) !== null && _c !== void 0 ? _c : '').trim();
|
|
20582
|
+
const value = (_e = (_d = c.get('value')) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : '';
|
|
20583
|
+
if (key !== '')
|
|
20584
|
+
params.set(key, value);
|
|
20585
|
+
}
|
|
20586
|
+
const queryString = params.toString();
|
|
20587
|
+
const newUrl = queryString ? `${baseUrl}?${queryString}` : baseUrl;
|
|
20588
|
+
if (this._url !== newUrl) {
|
|
20589
|
+
this._url = newUrl;
|
|
20590
|
+
this.cdr.markForCheck();
|
|
20591
|
+
}
|
|
20592
|
+
}
|
|
20231
20593
|
buildVerificationFormArray(rows) {
|
|
20232
20594
|
const defaultVerification = this.getDefaultVerification();
|
|
20233
20595
|
const defaultDataType = this.getDefaultDataType();
|
|
@@ -20262,16 +20624,154 @@ class ApiEditStepComponent {
|
|
|
20262
20624
|
this.headersFormArray = this.fb.array(groups);
|
|
20263
20625
|
}
|
|
20264
20626
|
}
|
|
20265
|
-
/**
|
|
20627
|
+
/** Reset all three steps and all entered data to initial/default state. Used when user cancels on step 1. */
|
|
20628
|
+
resetAllStepsAndData() {
|
|
20629
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
20630
|
+
this.currentStep = 1;
|
|
20631
|
+
const firstMethodValue = ((_a = this.httpMethodOptions) === null || _a === void 0 ? void 0 : _a.length)
|
|
20632
|
+
? ApiEditStepComponent.getOptionValue(this.httpMethodOptions[0])
|
|
20633
|
+
: undefined;
|
|
20634
|
+
const defaultMethod = (_d = (_c = this.initialMethod) !== null && _c !== void 0 ? _c : firstMethodValue) !== null && _d !== void 0 ? _d : 'GET';
|
|
20635
|
+
const methodVal = typeof defaultMethod === 'string' ? defaultMethod : ((_e = ApiEditStepComponent.getOptionValue(defaultMethod)) !== null && _e !== void 0 ? _e : '');
|
|
20636
|
+
this.currentMethodValue = methodVal !== null && methodVal !== void 0 ? methodVal : '';
|
|
20637
|
+
if (this.methodForm)
|
|
20638
|
+
this.methodForm.patchValue({ method: defaultMethod });
|
|
20639
|
+
const firstEnvValue = ((_f = this.environmentOptions) === null || _f === void 0 ? void 0 : _f.length)
|
|
20640
|
+
? ApiEditStepComponent.getOptionValue(this.environmentOptions[0])
|
|
20641
|
+
: undefined;
|
|
20642
|
+
const defaultEnv = (_h = (_g = this.initialEnvironment) !== null && _g !== void 0 ? _g : firstEnvValue) !== null && _h !== void 0 ? _h : 'Development';
|
|
20643
|
+
const envVal = typeof defaultEnv === 'string' ? defaultEnv : ((_j = ApiEditStepComponent.getOptionValue(defaultEnv)) !== null && _j !== void 0 ? _j : '');
|
|
20644
|
+
this.currentEnvironmentValue = envVal !== null && envVal !== void 0 ? envVal : '';
|
|
20645
|
+
if (this.environmentForm)
|
|
20646
|
+
this.environmentForm.patchValue({ environment: defaultEnv });
|
|
20647
|
+
this.url = (_k = this.initialUrl) !== null && _k !== void 0 ? _k : '';
|
|
20648
|
+
this.buildHeadersFormArray((_l = this.initialHeaders) !== null && _l !== void 0 ? _l : [{ name: '', type: 'string', value: '' }]);
|
|
20649
|
+
this.updateHeaderNameSelectConfig();
|
|
20650
|
+
this.headersChange.emit(this.headers);
|
|
20651
|
+
this.bodyView = 'headers';
|
|
20652
|
+
this.activePayloadTab = 'headers';
|
|
20653
|
+
this.payloadType = 'raw';
|
|
20654
|
+
this.payloadText = '';
|
|
20655
|
+
this.payloadJsonError = null;
|
|
20656
|
+
const defaultFormat = (_o = (_m = this.initialFormat) !== null && _m !== void 0 ? _m : this.getFormatValues()[0]) !== null && _o !== void 0 ? _o : 'json';
|
|
20657
|
+
if (this.payloadFormatForm)
|
|
20658
|
+
this.payloadFormatForm.patchValue({ format: defaultFormat });
|
|
20659
|
+
this.buildKeyValueFormArray();
|
|
20660
|
+
this.buildKeyTypeValueFormArray();
|
|
20661
|
+
this.buildParamsFormArray();
|
|
20662
|
+
this.importCurlControl.setValue('');
|
|
20663
|
+
this.variableName = '';
|
|
20664
|
+
this.variableNameError = '';
|
|
20665
|
+
this.buildVerificationFormArray();
|
|
20666
|
+
this.buildStatusVerificationFormArray();
|
|
20667
|
+
this.activeResponseVerificationTab = 'response-body';
|
|
20668
|
+
this.validatePayloadJson();
|
|
20669
|
+
this.cdr.detectChanges();
|
|
20670
|
+
}
|
|
20671
|
+
/** Handler: show import cURL panel (called when user clicks "Import API cURL"). Resets textarea so it is cleared each time. */
|
|
20266
20672
|
openImportCurlPanel() {
|
|
20673
|
+
this.importCurlControl.setValue('');
|
|
20267
20674
|
this.bodyView = 'import-curl';
|
|
20268
20675
|
this.cdr.detectChanges();
|
|
20269
20676
|
}
|
|
20270
|
-
/**
|
|
20677
|
+
/** Reset URL, method, headers, body, and params to empty/default before applying imported cURL. */
|
|
20678
|
+
resetRequestFieldsBeforeCurlImport() {
|
|
20679
|
+
var _a, _c, _d, _e, _f, _g, _h;
|
|
20680
|
+
const firstMethodValue = ((_a = this.httpMethodOptions) === null || _a === void 0 ? void 0 : _a.length)
|
|
20681
|
+
? ApiEditStepComponent.getOptionValue(this.httpMethodOptions[0])
|
|
20682
|
+
: undefined;
|
|
20683
|
+
const defaultMethod = (_d = (_c = this.initialMethod) !== null && _c !== void 0 ? _c : firstMethodValue) !== null && _d !== void 0 ? _d : 'GET';
|
|
20684
|
+
this.selectedMethod = typeof defaultMethod === 'string' ? defaultMethod : (_f = ((_e = ApiEditStepComponent.getOptionValue(defaultMethod)) !== null && _e !== void 0 ? _e : '')) !== null && _f !== void 0 ? _f : 'GET';
|
|
20685
|
+
this.currentMethodValue = this.selectedMethod;
|
|
20686
|
+
if (this.methodForm)
|
|
20687
|
+
this.methodForm.patchValue({ method: defaultMethod });
|
|
20688
|
+
this.url = '';
|
|
20689
|
+
this.buildHeadersFormArray([{ name: '', type: 'string', value: '' }]);
|
|
20690
|
+
this.updateHeaderNameSelectConfig();
|
|
20691
|
+
this.headersChange.emit(this.headers);
|
|
20692
|
+
this.payloadType = 'raw';
|
|
20693
|
+
this.payloadText = '';
|
|
20694
|
+
this.payloadJsonError = null;
|
|
20695
|
+
const defaultFormat = (_h = (_g = this.initialFormat) !== null && _g !== void 0 ? _g : this.getFormatValues()[0]) !== null && _h !== void 0 ? _h : 'json';
|
|
20696
|
+
if (this.payloadFormatForm)
|
|
20697
|
+
this.payloadFormatForm.patchValue({ format: defaultFormat });
|
|
20698
|
+
this.buildKeyValueFormArray([{ key: '', value: '' }]);
|
|
20699
|
+
this.buildKeyTypeValueFormArray([{ key: '', type: 'text', value: '' }]);
|
|
20700
|
+
this.buildParamsFormArray([{ key: '', value: '' }]);
|
|
20701
|
+
this.validatePayloadJson();
|
|
20702
|
+
this.cdr.detectChanges();
|
|
20703
|
+
}
|
|
20704
|
+
/** Handler: parse cURL from control, bind to form fields, emit and close panel. Called when user clicks Import button. */
|
|
20271
20705
|
onImportCurlConfirm() {
|
|
20272
|
-
var _a;
|
|
20706
|
+
var _a, _c, _d, _e, _f;
|
|
20273
20707
|
const value = (_a = this.importCurlControl.value) !== null && _a !== void 0 ? _a : '';
|
|
20274
|
-
|
|
20708
|
+
const curlStr = typeof value === 'string' ? value : '';
|
|
20709
|
+
this.importCurl.emit(curlStr);
|
|
20710
|
+
this.resetRequestFieldsBeforeCurlImport();
|
|
20711
|
+
const parsed = parseCurl(curlStr);
|
|
20712
|
+
if (parsed) {
|
|
20713
|
+
const methodValue = parsed.method && this.getMethodValues().includes(parsed.method)
|
|
20714
|
+
? parsed.method
|
|
20715
|
+
: parsed.method || 'GET';
|
|
20716
|
+
this.selectedMethod = methodValue;
|
|
20717
|
+
this.currentMethodValue = methodValue;
|
|
20718
|
+
if (parsed.url)
|
|
20719
|
+
this.url = parsed.url;
|
|
20720
|
+
// Bind Authorization header to Authorization section when present (Bearer or other scheme)
|
|
20721
|
+
let headerRows = parsed.headers;
|
|
20722
|
+
const authHeader = headerRows.find((h) => h.name.toLowerCase() === 'authorization');
|
|
20723
|
+
if ((_c = authHeader === null || authHeader === void 0 ? void 0 : authHeader.value) === null || _c === void 0 ? void 0 : _c.trim()) {
|
|
20724
|
+
const authValue = authHeader.value.trim();
|
|
20725
|
+
const bearerMatch = /^Bearer\s+(.+)$/i.exec(authValue);
|
|
20726
|
+
if (bearerMatch) {
|
|
20727
|
+
const token = bearerMatch[1].trim();
|
|
20728
|
+
if (this.getAuthTypeValues().includes('bearer') && this.authTypeForm) {
|
|
20729
|
+
this.authTypeForm.patchValue({ authType: 'bearer' });
|
|
20730
|
+
this.bearerToken = token;
|
|
20731
|
+
}
|
|
20732
|
+
headerRows = headerRows.filter((h) => h.name.toLowerCase() !== 'authorization');
|
|
20733
|
+
}
|
|
20734
|
+
}
|
|
20735
|
+
headerRows = headerRows.length > 0 ? headerRows : [{ name: '', type: 'string', value: '' }];
|
|
20736
|
+
this.buildHeadersFormArray(headerRows);
|
|
20737
|
+
this.updateHeaderNameSelectConfig();
|
|
20738
|
+
this.headersChange.emit(this.headers);
|
|
20739
|
+
if (parsed.body) {
|
|
20740
|
+
const contentType = (_f = (_e = (_d = parsed.headers
|
|
20741
|
+
.find((h) => h.name.toLowerCase() === 'content-type')) === null || _d === void 0 ? void 0 : _d.value) === null || _e === void 0 ? void 0 : _e.toLowerCase()) !== null && _f !== void 0 ? _f : '';
|
|
20742
|
+
const isFormUrlEncoded = contentType.includes('application/x-www-form-urlencoded');
|
|
20743
|
+
if (isFormUrlEncoded) {
|
|
20744
|
+
const rows = this.parseFormUrlEncodedBody(parsed.body);
|
|
20745
|
+
this.buildKeyValueFormArray(rows.length > 0 ? rows : [{ key: '', value: '' }]);
|
|
20746
|
+
const decodedAsJson = this.tryFormBodyValueAsRawJson(rows);
|
|
20747
|
+
if (decodedAsJson != null) {
|
|
20748
|
+
this.payloadType = 'raw';
|
|
20749
|
+
this.payloadText = decodedAsJson;
|
|
20750
|
+
if (this.payloadFormatForm)
|
|
20751
|
+
this.payloadFormatForm.patchValue({ format: 'json' });
|
|
20752
|
+
this.validatePayloadJson();
|
|
20753
|
+
this.payloadJsonError = null;
|
|
20754
|
+
}
|
|
20755
|
+
else {
|
|
20756
|
+
this.payloadType = 'x-www-form-urlencoded';
|
|
20757
|
+
this.payloadText = '';
|
|
20758
|
+
this.payloadJsonError = null;
|
|
20759
|
+
}
|
|
20760
|
+
}
|
|
20761
|
+
else {
|
|
20762
|
+
this.payloadText = parsed.body;
|
|
20763
|
+
this.validatePayloadJson();
|
|
20764
|
+
const trimmed = parsed.body.trim();
|
|
20765
|
+
if ((trimmed.startsWith('{') && trimmed.endsWith('}')) || (trimmed.startsWith('[') && trimmed.endsWith(']'))) {
|
|
20766
|
+
const formatValues = this.getFormatValues();
|
|
20767
|
+
if (formatValues.includes('json') && this.payloadFormatForm) {
|
|
20768
|
+
this.payloadFormatForm.patchValue({ format: 'json' });
|
|
20769
|
+
}
|
|
20770
|
+
}
|
|
20771
|
+
}
|
|
20772
|
+
}
|
|
20773
|
+
this.cdr.detectChanges();
|
|
20774
|
+
}
|
|
20275
20775
|
this.closeImportCurlPanel();
|
|
20276
20776
|
}
|
|
20277
20777
|
/** Handler: emit cancel and close panel. Called when user clicks Cancel in import cURL panel. */
|
|
@@ -20303,9 +20803,15 @@ class ApiEditStepComponent {
|
|
|
20303
20803
|
this.setStep(this.currentStep - 1);
|
|
20304
20804
|
}
|
|
20305
20805
|
else {
|
|
20806
|
+
this.resetAllStepsAndData();
|
|
20306
20807
|
this.back.emit();
|
|
20307
20808
|
}
|
|
20308
20809
|
}
|
|
20810
|
+
/** Called when user clicks the Cancel button (step 1). Emits cancel then runs normal back flow. */
|
|
20811
|
+
onCancel() {
|
|
20812
|
+
this.cancel.emit();
|
|
20813
|
+
this.onBack();
|
|
20814
|
+
}
|
|
20309
20815
|
onNext() {
|
|
20310
20816
|
var _a;
|
|
20311
20817
|
if (this.currentStep === 2 && !((_a = this.variableName) === null || _a === void 0 ? void 0 : _a.trim())) {
|
|
@@ -20360,6 +20866,15 @@ class ApiEditStepComponent {
|
|
|
20360
20866
|
trackByKeyTypeValue(index) {
|
|
20361
20867
|
return index;
|
|
20362
20868
|
}
|
|
20869
|
+
addParamsRow() {
|
|
20870
|
+
this.paramsFormArray.push(this.fb.group({ key: [''], value: [''] }));
|
|
20871
|
+
}
|
|
20872
|
+
removeParamsRow(index) {
|
|
20873
|
+
this.paramsFormArray.removeAt(index);
|
|
20874
|
+
}
|
|
20875
|
+
trackByParams(index) {
|
|
20876
|
+
return index;
|
|
20877
|
+
}
|
|
20363
20878
|
addVerificationRow() {
|
|
20364
20879
|
this.verificationFormArray.push(this.fb.group({
|
|
20365
20880
|
jsonPath: [''],
|
|
@@ -20405,21 +20920,25 @@ class ApiEditStepComponent {
|
|
|
20405
20920
|
}
|
|
20406
20921
|
/** Minimal payload when getCreatePayload throws (so create always emits). */
|
|
20407
20922
|
getCreatePayloadFallback() {
|
|
20408
|
-
var _a,
|
|
20923
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
20924
|
+
const authType = this.selectedAuthType;
|
|
20925
|
+
const bearerToken = authType === 'bearer' ? ((_a = this.bearerToken) !== null && _a !== void 0 ? _a : '') : undefined;
|
|
20926
|
+
let oauth2;
|
|
20927
|
+
if (authType === 'oauth2' && this.oauth2Form) {
|
|
20928
|
+
const grantType = ApiEditStepComponent.getControlValue(this.oauth2Form.get('grantType'));
|
|
20929
|
+
const clientAuth = ApiEditStepComponent.getControlValue(this.oauth2Form.get('clientAuthentication'));
|
|
20930
|
+
oauth2 = {
|
|
20931
|
+
grantType: grantType !== '' ? grantType : 'client_credentials',
|
|
20932
|
+
accessTokenUrl: ((_d = (_c = this.oauth2Form.get('accessTokenUrl')) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : ''),
|
|
20933
|
+
clientId: ((_f = (_e = this.oauth2Form.get('clientId')) === null || _e === void 0 ? void 0 : _e.value) !== null && _f !== void 0 ? _f : ''),
|
|
20934
|
+
clientSecret: ((_h = (_g = this.oauth2Form.get('clientSecret')) === null || _g === void 0 ? void 0 : _g.value) !== null && _h !== void 0 ? _h : ''),
|
|
20935
|
+
scope: ((_k = (_j = this.oauth2Form.get('scope')) === null || _j === void 0 ? void 0 : _j.value) !== null && _k !== void 0 ? _k : ''),
|
|
20936
|
+
clientAuthentication: clientAuth !== '' ? clientAuth : 'basic',
|
|
20937
|
+
};
|
|
20938
|
+
}
|
|
20409
20939
|
return {
|
|
20410
|
-
step1: {
|
|
20411
|
-
|
|
20412
|
-
method: '',
|
|
20413
|
-
url: (_a = this.url) !== null && _a !== void 0 ? _a : '',
|
|
20414
|
-
headers: [],
|
|
20415
|
-
activePayloadTab: this.activePayloadTab,
|
|
20416
|
-
payloadType: this.payloadType,
|
|
20417
|
-
payloadFormat: '',
|
|
20418
|
-
payloadText: (_b = this.payloadText) !== null && _b !== void 0 ? _b : '',
|
|
20419
|
-
keyValueRows: [],
|
|
20420
|
-
keyTypeValueRows: [],
|
|
20421
|
-
},
|
|
20422
|
-
step2: { variableName: (_c = this.variableName) !== null && _c !== void 0 ? _c : '' },
|
|
20940
|
+
step1: Object.assign(Object.assign(Object.assign({ environment: '', method: '', url: (_l = this.url) !== null && _l !== void 0 ? _l : '', headers: [], authType }, (bearerToken !== undefined && { bearerToken })), (oauth2 !== undefined && { oauth2 })), { activePayloadTab: this.activePayloadTab, payloadType: this.payloadType, payloadFormat: '', payloadText: (_m = this.payloadText) !== null && _m !== void 0 ? _m : '', keyValueRows: [], keyTypeValueRows: [], paramsRows: [] }),
|
|
20941
|
+
step2: { variableName: (_o = this.variableName) !== null && _o !== void 0 ? _o : '' },
|
|
20423
20942
|
step3: {
|
|
20424
20943
|
activeResponseVerificationTab: this.activeResponseVerificationTab,
|
|
20425
20944
|
responseBodyVerifications: [],
|
|
@@ -20437,62 +20956,77 @@ class ApiEditStepComponent {
|
|
|
20437
20956
|
}
|
|
20438
20957
|
/** Build full create payload: environment, HTTP method, URL, headers, body (step1), variable name (step2), verifications (step3). */
|
|
20439
20958
|
getCreatePayload() {
|
|
20440
|
-
var _a,
|
|
20959
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
|
|
20441
20960
|
const envFromForm = ApiEditStepComponent.getControlValue((_a = this.environmentForm) === null || _a === void 0 ? void 0 : _a.get('environment'));
|
|
20442
20961
|
const environment = envFromForm !== '' ? envFromForm : (this.currentEnvironmentValue !== '' ? this.currentEnvironmentValue : this.selectedEnvironment);
|
|
20443
|
-
const methodFromForm = ApiEditStepComponent.getControlValue((
|
|
20962
|
+
const methodFromForm = ApiEditStepComponent.getControlValue((_c = this.methodForm) === null || _c === void 0 ? void 0 : _c.get('method'));
|
|
20444
20963
|
const method = methodFromForm !== '' ? methodFromForm : (this.currentMethodValue !== '' ? this.currentMethodValue : this.selectedMethod);
|
|
20445
|
-
const format = (
|
|
20964
|
+
const format = (_f = (_e = (_d = this.payloadFormatForm) === null || _d === void 0 ? void 0 : _d.get('format')) === null || _e === void 0 ? void 0 : _e.value) !== null && _f !== void 0 ? _f : '';
|
|
20446
20965
|
const keyValueFormArray = this.keyValueFormArray;
|
|
20447
|
-
const keyValueRows = ((
|
|
20448
|
-
var _a,
|
|
20966
|
+
const keyValueRows = ((_g = keyValueFormArray === null || keyValueFormArray === void 0 ? void 0 : keyValueFormArray.controls) !== null && _g !== void 0 ? _g : []).map((c) => {
|
|
20967
|
+
var _a, _c, _d, _e;
|
|
20449
20968
|
return ({
|
|
20450
|
-
key: (
|
|
20451
|
-
value: (
|
|
20969
|
+
key: (_c = (_a = c.get('key')) === null || _a === void 0 ? void 0 : _a.value) !== null && _c !== void 0 ? _c : '',
|
|
20970
|
+
value: (_e = (_d = c.get('value')) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : '',
|
|
20452
20971
|
});
|
|
20453
20972
|
});
|
|
20454
20973
|
const keyTypeValueFormArray = this.keyTypeValueFormArray;
|
|
20455
|
-
const keyTypeValueRows = ((
|
|
20456
|
-
var _a,
|
|
20974
|
+
const keyTypeValueRows = ((_h = keyTypeValueFormArray === null || keyTypeValueFormArray === void 0 ? void 0 : keyTypeValueFormArray.controls) !== null && _h !== void 0 ? _h : []).map((c) => {
|
|
20975
|
+
var _a, _c, _d, _e, _f, _g;
|
|
20457
20976
|
return ({
|
|
20458
|
-
key: (
|
|
20459
|
-
type: (
|
|
20460
|
-
value: (
|
|
20977
|
+
key: (_c = (_a = c.get('key')) === null || _a === void 0 ? void 0 : _a.value) !== null && _c !== void 0 ? _c : '',
|
|
20978
|
+
type: (_e = (_d = c.get('type')) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : 'text',
|
|
20979
|
+
value: (_g = (_f = c.get('value')) === null || _f === void 0 ? void 0 : _f.value) !== null && _g !== void 0 ? _g : '',
|
|
20980
|
+
});
|
|
20981
|
+
});
|
|
20982
|
+
const paramsFormArray = this.paramsFormArray;
|
|
20983
|
+
const paramsRows = ((_j = paramsFormArray === null || paramsFormArray === void 0 ? void 0 : paramsFormArray.controls) !== null && _j !== void 0 ? _j : []).map((c) => {
|
|
20984
|
+
var _a, _c, _d, _e;
|
|
20985
|
+
return ({
|
|
20986
|
+
key: (_c = (_a = c.get('key')) === null || _a === void 0 ? void 0 : _a.value) !== null && _c !== void 0 ? _c : '',
|
|
20987
|
+
value: (_e = (_d = c.get('value')) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : '',
|
|
20461
20988
|
});
|
|
20462
20989
|
});
|
|
20463
20990
|
const verificationFormArray = this.verificationFormArray;
|
|
20464
|
-
const responseBodyVerifications = ((
|
|
20465
|
-
var _a,
|
|
20991
|
+
const responseBodyVerifications = ((_k = verificationFormArray === null || verificationFormArray === void 0 ? void 0 : verificationFormArray.controls) !== null && _k !== void 0 ? _k : []).map((c) => {
|
|
20992
|
+
var _a, _c, _d, _e, _f, _g, _h, _j;
|
|
20466
20993
|
return ({
|
|
20467
|
-
jsonPath: (
|
|
20468
|
-
verification: (
|
|
20469
|
-
dataType: (
|
|
20470
|
-
expectedValue: (
|
|
20994
|
+
jsonPath: (_c = (_a = c.get('jsonPath')) === null || _a === void 0 ? void 0 : _a.value) !== null && _c !== void 0 ? _c : '',
|
|
20995
|
+
verification: (_e = (_d = c.get('verification')) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : '',
|
|
20996
|
+
dataType: (_g = (_f = c.get('dataType')) === null || _f === void 0 ? void 0 : _f.value) !== null && _g !== void 0 ? _g : '',
|
|
20997
|
+
expectedValue: (_j = (_h = c.get('expectedValue')) === null || _h === void 0 ? void 0 : _h.value) !== null && _j !== void 0 ? _j : '',
|
|
20471
20998
|
});
|
|
20472
20999
|
});
|
|
20473
21000
|
const statusVerificationFormArray = this.statusVerificationFormArray;
|
|
20474
|
-
const statusVerifications = ((
|
|
20475
|
-
var _a,
|
|
21001
|
+
const statusVerifications = ((_l = statusVerificationFormArray === null || statusVerificationFormArray === void 0 ? void 0 : statusVerificationFormArray.controls) !== null && _l !== void 0 ? _l : []).map((c) => {
|
|
21002
|
+
var _a, _c, _d, _e;
|
|
20476
21003
|
return ({
|
|
20477
|
-
verification: (
|
|
20478
|
-
expectedValue: (
|
|
21004
|
+
verification: (_c = (_a = c.get('verification')) === null || _a === void 0 ? void 0 : _a.value) !== null && _c !== void 0 ? _c : '',
|
|
21005
|
+
expectedValue: (_e = (_d = c.get('expectedValue')) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : '',
|
|
20479
21006
|
});
|
|
20480
21007
|
});
|
|
21008
|
+
const authType = this.selectedAuthType;
|
|
21009
|
+
const bearerToken = authType === 'bearer' ? ((_m = this.bearerToken) !== null && _m !== void 0 ? _m : '') : undefined;
|
|
21010
|
+
let oauth2;
|
|
21011
|
+
if (authType === 'oauth2' && this.oauth2Form) {
|
|
21012
|
+
const grantType = ApiEditStepComponent.getControlValue(this.oauth2Form.get('grantType'));
|
|
21013
|
+
const clientAuth = ApiEditStepComponent.getControlValue(this.oauth2Form.get('clientAuthentication'));
|
|
21014
|
+
oauth2 = {
|
|
21015
|
+
grantType: grantType !== '' ? grantType : 'client_credentials',
|
|
21016
|
+
accessTokenUrl: ((_p = (_o = this.oauth2Form.get('accessTokenUrl')) === null || _o === void 0 ? void 0 : _o.value) !== null && _p !== void 0 ? _p : ''),
|
|
21017
|
+
clientId: ((_r = (_q = this.oauth2Form.get('clientId')) === null || _q === void 0 ? void 0 : _q.value) !== null && _r !== void 0 ? _r : ''),
|
|
21018
|
+
clientSecret: ((_t = (_s = this.oauth2Form.get('clientSecret')) === null || _s === void 0 ? void 0 : _s.value) !== null && _t !== void 0 ? _t : ''),
|
|
21019
|
+
scope: ((_v = (_u = this.oauth2Form.get('scope')) === null || _u === void 0 ? void 0 : _u.value) !== null && _v !== void 0 ? _v : ''),
|
|
21020
|
+
clientAuthentication: clientAuth !== '' ? clientAuth : 'basic',
|
|
21021
|
+
};
|
|
21022
|
+
}
|
|
20481
21023
|
return {
|
|
20482
|
-
step1: {
|
|
20483
|
-
|
|
20484
|
-
method,
|
|
20485
|
-
url: (_k = this.url) !== null && _k !== void 0 ? _k : '',
|
|
20486
|
-
headers: this.headers,
|
|
20487
|
-
activePayloadTab: this.activePayloadTab,
|
|
20488
|
-
payloadType: this.payloadType,
|
|
20489
|
-
payloadFormat: format,
|
|
20490
|
-
payloadText: (_l = this.payloadText) !== null && _l !== void 0 ? _l : '',
|
|
20491
|
-
keyValueRows,
|
|
21024
|
+
step1: Object.assign(Object.assign(Object.assign({ environment,
|
|
21025
|
+
method, url: (_w = this.url) !== null && _w !== void 0 ? _w : '', headers: this.headers, authType }, (bearerToken !== undefined && { bearerToken })), (oauth2 !== undefined && { oauth2 })), { activePayloadTab: this.activePayloadTab, payloadType: this.payloadType, payloadFormat: format, payloadText: (_x = this.payloadText) !== null && _x !== void 0 ? _x : '', keyValueRows,
|
|
20492
21026
|
keyTypeValueRows,
|
|
20493
|
-
|
|
21027
|
+
paramsRows }),
|
|
20494
21028
|
step2: {
|
|
20495
|
-
variableName: (
|
|
21029
|
+
variableName: (_y = this.variableName) !== null && _y !== void 0 ? _y : '',
|
|
20496
21030
|
},
|
|
20497
21031
|
step3: {
|
|
20498
21032
|
activeResponseVerificationTab: this.activeResponseVerificationTab,
|
|
@@ -20506,25 +21040,25 @@ class ApiEditStepComponent {
|
|
|
20506
21040
|
if (!this.headersFormArray)
|
|
20507
21041
|
return [];
|
|
20508
21042
|
return this.headersFormArray.controls.map((c) => {
|
|
20509
|
-
var _a,
|
|
21043
|
+
var _a, _c, _d, _e;
|
|
20510
21044
|
return ({
|
|
20511
|
-
name: (
|
|
21045
|
+
name: (_c = (_a = c.get('name')) === null || _a === void 0 ? void 0 : _a.value) !== null && _c !== void 0 ? _c : '',
|
|
20512
21046
|
type: 'string',
|
|
20513
|
-
value: (
|
|
21047
|
+
value: (_e = (_d = c.get('value')) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : '',
|
|
20514
21048
|
});
|
|
20515
21049
|
});
|
|
20516
21050
|
}
|
|
20517
21051
|
ngOnChanges(changes) {
|
|
20518
|
-
var _a,
|
|
21052
|
+
var _a, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
20519
21053
|
if (((_a = changes['initialMethod']) === null || _a === void 0 ? void 0 : _a.currentValue) != null && this.methodForm) {
|
|
20520
21054
|
const v = changes['initialMethod'].currentValue;
|
|
20521
|
-
this.currentMethodValue = typeof v === 'string' ? v : ((
|
|
21055
|
+
this.currentMethodValue = typeof v === 'string' ? v : ((_c = ApiEditStepComponent.getOptionValue(v)) !== null && _c !== void 0 ? _c : '');
|
|
20522
21056
|
this.methodForm.patchValue({ method: v });
|
|
20523
21057
|
}
|
|
20524
21058
|
if (changes['httpMethodOptions']) {
|
|
20525
21059
|
this.updateMethodSelectConfig();
|
|
20526
|
-
if (this.methodForm && ((
|
|
20527
|
-
const current = (
|
|
21060
|
+
if (this.methodForm && ((_d = this.httpMethodOptions) === null || _d === void 0 ? void 0 : _d.length)) {
|
|
21061
|
+
const current = (_e = this.methodForm.get('method')) === null || _e === void 0 ? void 0 : _e.value;
|
|
20528
21062
|
const values = this.getMethodValues();
|
|
20529
21063
|
const valid = values.includes(current);
|
|
20530
21064
|
if (!valid) {
|
|
@@ -20536,15 +21070,15 @@ class ApiEditStepComponent {
|
|
|
20536
21070
|
}
|
|
20537
21071
|
}
|
|
20538
21072
|
}
|
|
20539
|
-
if (((
|
|
21073
|
+
if (((_f = changes['initialEnvironment']) === null || _f === void 0 ? void 0 : _f.currentValue) != null && this.environmentForm) {
|
|
20540
21074
|
const v = changes['initialEnvironment'].currentValue;
|
|
20541
|
-
this.currentEnvironmentValue = typeof v === 'string' ? v : ((
|
|
21075
|
+
this.currentEnvironmentValue = typeof v === 'string' ? v : ((_g = ApiEditStepComponent.getOptionValue(v)) !== null && _g !== void 0 ? _g : '');
|
|
20542
21076
|
this.environmentForm.patchValue({ environment: v });
|
|
20543
21077
|
}
|
|
20544
21078
|
if (changes['environmentOptions']) {
|
|
20545
21079
|
this.updateEnvironmentSelectConfig();
|
|
20546
|
-
if (this.environmentForm && ((
|
|
20547
|
-
const current = (
|
|
21080
|
+
if (this.environmentForm && ((_h = this.environmentOptions) === null || _h === void 0 ? void 0 : _h.length)) {
|
|
21081
|
+
const current = (_j = this.environmentForm.get('environment')) === null || _j === void 0 ? void 0 : _j.value;
|
|
20548
21082
|
const values = this.getEnvironmentValues();
|
|
20549
21083
|
const valid = values.includes(current);
|
|
20550
21084
|
if (!valid) {
|
|
@@ -20556,32 +21090,62 @@ class ApiEditStepComponent {
|
|
|
20556
21090
|
}
|
|
20557
21091
|
}
|
|
20558
21092
|
}
|
|
21093
|
+
if (((_k = changes['initialAuthType']) === null || _k === void 0 ? void 0 : _k.currentValue) != null && this.authTypeForm) {
|
|
21094
|
+
const v = changes['initialAuthType'].currentValue;
|
|
21095
|
+
const resolved = typeof v === 'string' ? v : ApiEditStepComponent.getOptionValue(v);
|
|
21096
|
+
if (resolved != null)
|
|
21097
|
+
this.authTypeForm.patchValue({ authType: v });
|
|
21098
|
+
}
|
|
21099
|
+
if (changes['authTypeOptions']) {
|
|
21100
|
+
this.updateAuthTypeSelectConfig();
|
|
21101
|
+
if (this.authTypeForm) {
|
|
21102
|
+
const values = this.getAuthTypeValues();
|
|
21103
|
+
if (values.length > 0) {
|
|
21104
|
+
const current = (_l = this.authTypeForm.get('authType')) === null || _l === void 0 ? void 0 : _l.value;
|
|
21105
|
+
const currentVal = current != null && current !== ''
|
|
21106
|
+
? typeof current === 'object'
|
|
21107
|
+
? ApiEditStepComponent.getOptionValue(current)
|
|
21108
|
+
: String(current)
|
|
21109
|
+
: null;
|
|
21110
|
+
const valid = currentVal != null && values.includes(currentVal);
|
|
21111
|
+
if (!valid) {
|
|
21112
|
+
const firstValue = values[0];
|
|
21113
|
+
if (firstValue != null) {
|
|
21114
|
+
this.authTypeForm.patchValue({ authType: firstValue });
|
|
21115
|
+
}
|
|
21116
|
+
}
|
|
21117
|
+
}
|
|
21118
|
+
}
|
|
21119
|
+
}
|
|
20559
21120
|
if (changes['initialStep']) {
|
|
20560
21121
|
this.applyInitialStep(changes['initialStep'].currentValue);
|
|
20561
21122
|
}
|
|
20562
|
-
if (((
|
|
21123
|
+
if (((_m = changes['initialUrl']) === null || _m === void 0 ? void 0 : _m.currentValue) != null) {
|
|
20563
21124
|
this.url = changes['initialUrl'].currentValue;
|
|
20564
21125
|
}
|
|
20565
|
-
if (((
|
|
21126
|
+
if (((_o = changes['initialPayloadTab']) === null || _o === void 0 ? void 0 : _o.currentValue) != null) {
|
|
20566
21127
|
this.activePayloadTab = changes['initialPayloadTab'].currentValue;
|
|
20567
21128
|
}
|
|
20568
21129
|
if (changes['headerNameOptions']) {
|
|
20569
21130
|
this.updateHeaderNameSelectConfig();
|
|
20570
21131
|
}
|
|
20571
|
-
if (((
|
|
21132
|
+
if (((_p = changes['initialHeaders']) === null || _p === void 0 ? void 0 : _p.currentValue) != null) {
|
|
20572
21133
|
this.buildHeadersFormArray(changes['initialHeaders'].currentValue);
|
|
20573
21134
|
this.updateHeaderNameSelectConfig();
|
|
20574
21135
|
}
|
|
20575
|
-
if (((
|
|
21136
|
+
if (((_q = changes['initialResponsePreview']) === null || _q === void 0 ? void 0 : _q.currentValue) != null) {
|
|
20576
21137
|
this.responsePreview = changes['initialResponsePreview'].currentValue;
|
|
20577
21138
|
}
|
|
20578
|
-
if (((
|
|
21139
|
+
if (((_r = changes['initialFormat']) === null || _r === void 0 ? void 0 : _r.currentValue) != null && this.payloadFormatForm) {
|
|
20579
21140
|
this.payloadFormatForm.patchValue({ format: changes['initialFormat'].currentValue });
|
|
20580
21141
|
}
|
|
21142
|
+
if (((_s = changes['initialVariableName']) === null || _s === void 0 ? void 0 : _s.currentValue) != null) {
|
|
21143
|
+
this.variableName = changes['initialVariableName'].currentValue;
|
|
21144
|
+
}
|
|
20581
21145
|
if (changes['formatOptions']) {
|
|
20582
21146
|
this.updatePayloadFormatSelectConfig();
|
|
20583
21147
|
if (this.payloadFormatForm) {
|
|
20584
|
-
const current = (
|
|
21148
|
+
const current = (_t = this.payloadFormatForm.get('format')) === null || _t === void 0 ? void 0 : _t.value;
|
|
20585
21149
|
const values = this.getFormatValues();
|
|
20586
21150
|
const valid = values.includes(current);
|
|
20587
21151
|
if (!valid && values.length > 0) {
|
|
@@ -20634,6 +21198,24 @@ class ApiEditStepComponent {
|
|
|
20634
21198
|
}
|
|
20635
21199
|
}
|
|
20636
21200
|
}
|
|
21201
|
+
/** Default options when authTypeOptions is empty (same shape as environment) */
|
|
21202
|
+
ApiEditStepComponent.DEFAULT_AUTH_TYPE_OPTIONS = [
|
|
21203
|
+
{ id: 'no-auth', value: 'no-auth', name: 'No Auth', label: 'No Auth' },
|
|
21204
|
+
{ id: 'bearer', value: 'bearer', name: 'Bearer Token', label: 'Bearer Token' },
|
|
21205
|
+
{ id: 'oauth2', value: 'oauth2', name: 'OAuth 2.0', label: 'OAuth 2.0' },
|
|
21206
|
+
];
|
|
21207
|
+
/** Grant type options for OAuth 2.0 */
|
|
21208
|
+
ApiEditStepComponent.OAUTH_GRANT_TYPE_OPTIONS = [
|
|
21209
|
+
{ id: 'client_credentials', value: 'client_credentials', name: 'Client Credentials', label: 'Client Credentials' },
|
|
21210
|
+
{ id: 'authorization_code', value: 'authorization_code', name: 'Authorization Code', label: 'Authorization Code' },
|
|
21211
|
+
{ id: 'password', value: 'password', name: 'Password', label: 'Password' },
|
|
21212
|
+
{ id: 'implicit', value: 'implicit', name: 'Implicit', label: 'Implicit' },
|
|
21213
|
+
];
|
|
21214
|
+
/** Client authentication method options for OAuth 2.0 */
|
|
21215
|
+
ApiEditStepComponent.OAUTH_CLIENT_AUTH_OPTIONS = [
|
|
21216
|
+
{ id: 'basic', value: 'basic', name: 'Send as Basic Auth header', label: 'Send as Basic Auth header' },
|
|
21217
|
+
{ id: 'body', value: 'body', name: 'Send in body', label: 'Send in body' },
|
|
21218
|
+
];
|
|
20637
21219
|
ApiEditStepComponent.DEFAULT_FORMAT_OPTIONS = [
|
|
20638
21220
|
{ id: 'json', value: 'json', name: 'JSON', label: 'JSON' },
|
|
20639
21221
|
{ id: 'xml', value: 'xml', name: 'XML', label: 'XML' },
|
|
@@ -20647,7 +21229,7 @@ ApiEditStepComponent.DEFAULT_HEADER_NAME_OPTIONS = [
|
|
|
20647
21229
|
'Accept-Language',
|
|
20648
21230
|
'Access-Control-Request-Headers',
|
|
20649
21231
|
'Access-Control-Request-Method',
|
|
20650
|
-
'
|
|
21232
|
+
'Scripts',
|
|
20651
21233
|
'Cache-Control',
|
|
20652
21234
|
'Content-MD5',
|
|
20653
21235
|
'Content-Length',
|
|
@@ -20705,10 +21287,10 @@ ApiEditStepComponent.DEFAULT_STATUS_VERIFICATION_OPTIONS = [
|
|
|
20705
21287
|
{ id: 'greater-than', value: 'greater-than', name: 'Greater than', label: 'Greater than' },
|
|
20706
21288
|
];
|
|
20707
21289
|
ApiEditStepComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ApiEditStepComponent, deps: [{ token: i1$1.FormBuilder }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
20708
|
-
ApiEditStepComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ApiEditStepComponent, selector: "cqa-api-edit-step", inputs: { initialMethod: "initialMethod", initialEnvironment: "initialEnvironment", initialStep: "initialStep", initialUrl: "initialUrl", initialPayloadTab: "initialPayloadTab", initialHeaders: "initialHeaders", initialResponsePreview: "initialResponsePreview", httpMethodOptions: "httpMethodOptions", environmentOptions: "environmentOptions", formatOptions: "formatOptions", initialFormat: "initialFormat", headerNameOptions: "headerNameOptions", verificationOptions: "verificationOptions", verificationDataTypeOptions: "verificationDataTypeOptions", statusVerificationOptions: "statusVerificationOptions" }, outputs: { importCurl: "importCurl", importCurlCancel: "importCurlCancel", sendRequest: "sendRequest", back: "back", next: "next", create: "create", headersChange: "headersChange" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "payloadEditorWithLinesRef", first: true, predicate: ["payloadEditorWithLinesRef"], descendants: true }, { propertyName: "payloadTextareaRef", first: true, predicate: ["payloadTextareaRef"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-api-edit-step-container\">\n <!-- Title -->\n <h2\n class=\"cqa-api-edit-step-title cqa-font-inter cqa-text-[12px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal cqa-text-[#000000]\">\n Create API Test Step</h2>\n\n <!-- Step indicator: all three steps visible, active step highlighted (Postman-style) -->\n <div class=\"cqa-api-edit-step-indicator\">\n <ng-container *ngFor=\"let step of stepLabels; let i = index\">\n <cqa-button type=\"button\" variant=\"text\"\n customClass=\"cqa-api-edit-step-indicator-item cqa-api-edit-step-indicator-item--clickable\"\n [attr.aria-label]=\"'Step ' + step.index + ': ' + step.label\" [attr.aria-pressed]=\"step.index === currentStep\"\n (clicked)=\"setStep(step.index)\">\n <span class=\"cqa-api-edit-step-indicator-circle\"\n [class.cqa-api-edit-step-indicator-circle--active]=\"step.index === currentStep\">\n {{ step.index }}\n </span>\n <span class=\"cqa-api-edit-step-indicator-label\"\n [class.cqa-api-edit-step-indicator-label--active]=\"step.index === currentStep\">\n {{ step.label }}\n </span>\n <div *ngIf=\"i < stepLabels.length - 1\" class=\"cqa-api-edit-step-indicator-line\" aria-hidden=\"true\"></div>\n </cqa-button>\n </ng-container>\n </div>\n\n <!-- Step content viewport: smooth slide between steps -->\n <div class=\"cqa-api-edit-step-viewport\">\n <div class=\"cqa-api-edit-step-strip\" [style.transform]=\"'translateX(' + stripTranslatePercent + '%)'\">\n <!-- Step 1: Environment, request, body, response -->\n <div class=\"cqa-api-edit-step-panel\">\n <!-- Environment row: new line, select aligned right -->\n <div class=\"cqa-api-edit-step-environment-row\">\n <cqa-dynamic-select *ngIf=\"environmentForm\" [form]=\"environmentForm\" [config]=\"environmentSelectConfig\"\n class=\"cqa-api-edit-step-environment-select\" aria-label=\"Environment\"\n (selectionChange)=\"onEnvironmentSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Request row: method, URL, buttons -->\n <div class=\"cqa-api-edit-step-request-row\">\n <cqa-dynamic-select *ngIf=\"methodForm\" [form]=\"methodForm\" [config]=\"methodSelectConfig\"\n class=\"cqa-api-edit-step-method-select\" aria-label=\"HTTP method\"\n (selectionChange)=\"onMethodSelectionChange($event)\">\n </cqa-dynamic-select>\n <div class=\"cqa-api-edit-step-url-wrap\">\n <cqa-custom-input [(value)]=\"url\" [label]=\"''\" placeholder=\"\" [fullWidth]=\"true\" size=\"md\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-trigger\" style=\"display: contents\" (click)=\"openImportCurlPanel()\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Import API cURL\"\n customClass=\"cqa-api-edit-step-btn-outline cqa-font-inter cqa-text-[14px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal cqa-text-[#414146]\">\n </cqa-button>\n </div>\n <cqa-button variant=\"filled\" btnSize=\"lg\" text=\"Send Request\" (clicked)=\"onSendRequest()\"\n customClass=\"cqa-api-edit-step-btn-primary cqa-font-inter cqa-text-[14px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal cqa-text-[#FBFCFF]\">\n </cqa-button>\n </div>\n\n\n\n <!-- Body content: header section (default) OR import cURL section -->\n <ng-container *ngIf=\"bodyView === 'import-curl'\">\n <div class=\"cqa-api-edit-step-import-curl-panel\">\n <div class=\"cqa-api-edit-step-import-curl-header\">\n <h3 class=\"cqa-api-edit-step-import-curl-title\">Import API cURL</h3>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-separator\"></div>\n <div class=\"cqa-api-edit-step-import-curl-body\">\n <cqa-custom-textarea [value]=\"importCurlControl.value\"\n (valueChange)=\"importCurlControl.setValue($event)\"\n placeholder=\"Paste your cURL command here (e.g., curl -X POST https://api.example.com/users)\"\n [fullWidth]=\"true\" [rows]=\"8\" resize=\"vertical\" size=\"md\"\n class=\"cqa-api-edit-step-import-curl-textarea\">\n </cqa-custom-textarea>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-footer\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Cancel\"\n customClass=\"cqa-api-edit-step-import-curl-btn-cancel\" (clicked)=\"onCancelImportCurl()\"></cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Import\"\n customClass=\"cqa-api-edit-step-import-curl-btn-import\" (clicked)=\"onImportCurlConfirm()\"></cqa-button>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"bodyView === 'headers'\">\n <div class=\"cqa-api-edit-step-tabs-wrapper\">\n <div class=\"cqa-api-edit-step-tabs\">\n <cqa-button *ngFor=\"let tab of payloadTabs\" type=\"button\" variant=\"text\" [text]=\"tab.label\"\n [customClass]=\"'cqa-api-edit-step-tab' + (activePayloadTab === tab.value ? ' cqa-api-edit-step-tab--active' : '') + (isMethodWithoutBody && tab.value !== 'headers' ? ' cqa-api-edit-step-tab--disabled' : '')\"\n [disabled]=\"isMethodWithoutBody && tab.value !== 'headers'\"\n (clicked)=\"setPayloadTab(tab.value)\">\n </cqa-button>\n </div>\n\n <!-- Payload content (Headers) -->\n <div *ngIf=\"activePayloadTab === 'headers'\" class=\"cqa-api-edit-step-payload\">\n <div class=\"cqa-api-edit-step-headers-grid\">\n <span class=\"cqa-api-edit-step-headers-label\">Header Name</span>\n <span class=\"cqa-api-edit-step-headers-label\">Header Value</span>\n <span class=\"cqa-api-edit-step-headers-label cqa-api-edit-step-headers-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of headerRows; let i = index; trackBy: trackByHeader\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-header-row\">\n <cqa-dynamic-select [form]=\"row\" [config]=\"headerNameSelectConfig\"\n (addCustomValue)=\"onHeaderNameAddCustomValue($event, row)\"\n class=\"cqa-api-edit-step-header-type-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-header-value-input\" ariaLabel=\"Header value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-header-delete'\"\n [tooltip]=\"'Remove header'\" (clicked)=\"removeHeader(i)\">\n <svg class=\"cqa-api-edit-step-header-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-add-header-wrap\">\n <cqa-button type=\"button\" variant=\"text\" text=\"+ Add Header\"\n [customClass]=\"'cqa-api-edit-step-add-header-link'\" (clicked)=\"addHeader()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Payload content (Body only): type, format, text area, Back/Next -->\n <div *ngIf=\"activePayloadTab === 'body'\"\n class=\"cqa-api-edit-step-payload cqa-api-edit-step-payload-editor\">\n <div class=\"cqa-api-edit-step-payload-type-row\">\n <span class=\"cqa-api-edit-step-payload-type-label\">Type</span>\n <div class=\"cqa-api-edit-step-payload-type-radios\">\n <cqa-segment-control [value]=\"payloadType\" [segments]=\"payloadTypeSegments\"\n (valueChange)=\"onPayloadTypeChange($event)\"\n class=\"cqa-api-edit-step-payload-type-segment\">\n </cqa-segment-control>\n </div>\n <div *ngIf=\"payloadType === 'raw'\" class=\"cqa-api-edit-step-payload-format-wrap\">\n <span class=\"cqa-api-edit-step-payload-format-label\">Format:</span>\n <cqa-dynamic-select *ngIf=\"payloadFormatForm\" [form]=\"payloadFormatForm\"\n [config]=\"payloadFormatSelectConfig\" class=\"cqa-api-edit-step-payload-format-select\"\n aria-label=\"Format\">\n </cqa-dynamic-select>\n </div>\n </div>\n <!-- Raw: text area with line numbers (Postman-style payload body) -->\n <div *ngIf=\"payloadType === 'raw'\" class=\"cqa-api-edit-step-payload-body\" #payloadEditorWithLinesRef>\n <div class=\"cqa-api-edit-step-payload-editor-with-lines\">\n <div class=\"cqa-api-edit-step-payload-line-numbers\" aria-hidden=\"true\">\n <span *ngFor=\"let n of payloadLineNumbers\" class=\"cqa-api-edit-step-payload-line-num\">\n <span *ngIf=\"payloadJsonError && payloadJsonError.line === n\"\n class=\"cqa-api-edit-step-payload-line-error-icon\" [title]=\"payloadJsonErrorTooltip\"\n aria-label=\"Parse error on this line\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"6\" fill=\"#EF4444\"/>\n <path d=\"M4 4l6 6M10 4l-6 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-api-edit-step-payload-line-num-text\">{{ n }}</span>\n </span>\n </div>\n <div class=\"cqa-api-edit-step-payload-textarea-cell\">\n <div class=\"cqa-api-edit-step-payload-textarea cqa-w-full cqa-flex cqa-flex-col cqa-min-h-0\"\n [ngClass]=\"{'cqa-api-edit-step-payload-textarea--error': payloadJsonError}\">\n <textarea #payloadTextareaRef\n class=\"cqa-api-edit-step-payload-textarea-input cqa-w-full cqa-resize-y cqa-outline-none cqa-box-border\"\n [ngClass]=\"{'cqa-api-edit-step-payload-textarea-input--error': payloadJsonError}\"\n [value]=\"payloadText\"\n [attr.rows]=\"10\"\n placeholder=\"\"\n [attr.aria-label]=\"'Payload'\"\n [attr.aria-invalid]=\"!!payloadJsonError\"\n (input)=\"onPayloadInput($event)\"\n (keydown)=\"onPayloadKeydown($event)\">\n </textarea>\n </div>\n </div>\n </div>\n <p *ngIf=\"payloadJsonError\" class=\"cqa-api-edit-step-payload-json-error-msg\">\n Invalid JSON format. Please check your syntax.\n </p>\n </div>\n\n <!-- x-www-form-urlencoded: Key\u2013Value rows, add/remove dynamically -->\n <div *ngIf=\"payloadType === 'x-www-form-urlencoded'\" class=\"cqa-api-edit-step-key-value\">\n <div class=\"cqa-api-edit-step-key-value-grid cqa-api-edit-step-key-value-header\">\n <span class=\"cqa-api-edit-step-key-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-value-label cqa-api-edit-step-key-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of keyValueRows; let i = index; trackBy: trackByKeyValue\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeKeyValueRow(i)\">\n <svg class=\"cqa-api-edit-step-key-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-value-add-btn\" (clicked)=\"addKeyValueRow()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Form Data: Key\u2013Type\u2013Value rows; Type is a dropdown (Text/File), add/remove dynamically -->\n <div *ngIf=\"payloadType === 'form-data'\" class=\"cqa-api-edit-step-key-type-value\">\n <div class=\"cqa-api-edit-step-key-type-value-header\">\n <span class=\"cqa-api-edit-step-key-type-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-type-value-label\">Type</span>\n <span class=\"cqa-api-edit-step-key-type-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-type-value-label cqa-api-edit-step-key-type-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of keyTypeValueRows; let i = index; trackBy: trackByKeyTypeValue\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-type-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-type-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"row\" [config]=\"keyTypeValueTypeSelectConfig\"\n class=\"cqa-api-edit-step-key-type-value-type-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-type-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-type-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeKeyTypeValueRow(i)\">\n <svg class=\"cqa-api-edit-step-key-type-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-type-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-type-value-add-btn\" (clicked)=\"addKeyTypeValueRow()\">\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n\n </div>\n <!-- Step 2: Variable Name: input, validation, Back / Next -->\n <div class=\"cqa-api-edit-step-panel\">\n <div class=\"cqa-api-edit-step-variable-section\">\n <div class=\"cqa-api-edit-step-variable-input-wrap\">\n <cqa-custom-input [(value)]=\"variableName\" [label]=\"''\" placeholder=\"Variable Name\" [fullWidth]=\"true\"\n size=\"md\" (valueChange)=\"onVariableNameChange()\" aria-label=\"Variable Name\">\n </cqa-custom-input>\n </div>\n <p *ngIf=\"variableNameError\" class=\"cqa-api-edit-step-variable-error\" role=\"alert\">{{ variableNameError }}</p>\n </div>\n </div>\n <!-- Step 3: Response Body / Status tabs -->\n <div class=\"cqa-api-edit-step-panel\">\n <div class=\"cqa-api-edit-step-tabs-wrapper\">\n <div class=\"cqa-api-edit-step-tabs\">\n <cqa-button *ngFor=\"let tab of responseVerificationTabs\" type=\"button\" variant=\"text\" [text]=\"tab.label\"\n [customClass]=\"'cqa-api-edit-step-tab' + (activeResponseVerificationTab === tab.value ? ' cqa-api-edit-step-tab--active' : '')\"\n (clicked)=\"setResponseVerificationTab(tab.value)\">\n </cqa-button>\n </div>\n\n <!-- Response Body tab content: verification grid -->\n <div *ngIf=\"activeResponseVerificationTab === 'response-body'\" class=\"cqa-api-edit-step-step3-content\">\n <div class=\"cqa-api-edit-step-verification-header-row\">\n <span></span>\n <cqa-button type=\"button\" variant=\"text\" text=\"Add Verification\"\n customClass=\"cqa-api-edit-step-verification-add-link\" (clicked)=\"addVerificationRow()\">\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-verification\">\n <div class=\"cqa-api-edit-step-verification-grid cqa-api-edit-step-verification-grid-header\">\n <span class=\"cqa-api-edit-step-verification-label\">S.no</span>\n <span class=\"cqa-api-edit-step-verification-label\">JSON Path</span>\n <span class=\"cqa-api-edit-step-verification-label\">Verification</span>\n <span class=\"cqa-api-edit-step-verification-label\">Data Type</span>\n <span class=\"cqa-api-edit-step-verification-label\">Expected Value</span>\n <span class=\"cqa-api-edit-step-verification-label cqa-api-edit-step-verification-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of verificationRows; let i = index; trackBy: trackByVerification\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-verification-row\">\n <span class=\"cqa-api-edit-step-verification-sno\">{{ i + 1 }}</span>\n <cqa-custom-input [value]=\"row.get('jsonPath')?.value ?? ''\"\n (valueChange)=\"row.get('jsonPath')?.setValue($event)\" placeholder=\"Json Path\" [fullWidth]=\"true\"\n size=\"sm\" class=\"cqa-api-edit-step-verification-input\" ariaLabel=\"JSON Path\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"row\" [config]=\"verificationSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-dynamic-select [form]=\"row\" [config]=\"verificationDataTypeSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-w-full\"\n (selectionChange)=\"onVerificationDataTypeChange(row, $event)\">\n </cqa-dynamic-select>\n <!-- Expected Value: text for String/Array/Object, number for Number, dropdown for Boolean -->\n <ng-container [ngSwitch]=\"row.get('dataType')?.value\">\n <cqa-dynamic-select *ngSwitchCase=\"'boolean'\" [form]=\"row\"\n [config]=\"verificationExpectedValueBooleanSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-api-edit-step-verification-expected-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input *ngSwitchCase=\"'number'\" [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\" placeholder=\"Expected Value (number)\"\n type=\"number\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-verification-input cqa-api-edit-step-verification-expected-number\"\n ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n <cqa-custom-input *ngSwitchDefault [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\"\n placeholder=\"Expected Value in String\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-verification-input\" ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n </ng-container>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-verification-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeVerificationRow(i)\">\n <svg class=\"cqa-api-edit-step-verification-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n </div>\n </div>\n\n <!-- Status tab content: S.no, Verification dropdown, Expected Value, add/remove rows -->\n <div *ngIf=\"activeResponseVerificationTab === 'status'\" class=\"cqa-api-edit-step-step3-content\">\n <div class=\"cqa-api-edit-step-verification-header-row\">\n <span></span>\n <cqa-button type=\"button\" variant=\"text\" text=\"Add Verification\"\n customClass=\"cqa-api-edit-step-verification-add-link\" (clicked)=\"addStatusVerificationRow()\">\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-status-verification\">\n <div class=\"cqa-api-edit-step-status-verification-header\">\n <span class=\"cqa-api-edit-step-verification-label\">S.no</span>\n <span class=\"cqa-api-edit-step-verification-label\">Verification</span>\n <span class=\"cqa-api-edit-step-verification-label\">Expected Value</span>\n <span class=\"cqa-api-edit-step-verification-label cqa-api-edit-step-verification-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of statusVerificationRows; let i = index; trackBy: trackByStatusVerification\"\n [formGroup]=\"row\" class=\"cqa-api-edit-step-status-verification-row\">\n <span class=\"cqa-api-edit-step-verification-sno\">{{ i + 1 }}</span>\n <cqa-dynamic-select [form]=\"row\" [config]=\"statusVerificationSelectConfig\"\n class=\"cqa-api-edit-step-status-verification-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\" placeholder=\"Expected Value\"\n type=\"number\" [fullWidth]=\"true\" size=\"sm\" class=\"cqa-api-edit-step-verification-input\"\n ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-verification-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeStatusVerificationRow(i)\">\n <svg class=\"cqa-api-edit-step-verification-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Response Preview -->\n <div class=\"cqa-api-edit-step-response\">\n <h3 class=\"cqa-api-edit-step-response-title\">Response Preview</h3>\n <pre class=\"cqa-api-edit-step-response-content\">{{ responsePreview }}</pre>\n </div>\n\n <!-- Step actions: one row, full width. Step 1: Cancel + Next; Step 2: Back + Next; Step 3: Back + Create -->\n <div class=\"cqa-api-edit-step-actions\">\n <ng-container [ngSwitch]=\"currentStep\">\n <ng-container *ngSwitchCase=\"1\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Cancel\"\n customClass=\"cqa-api-edit-step-actions-btn-cancel\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Next\"\n customClass=\"cqa-api-edit-step-actions-btn-next\" (clicked)=\"onNext()\">\n </cqa-button>\n </ng-container>\n <ng-container *ngSwitchCase=\"2\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Back\"\n customClass=\"cqa-api-edit-step-actions-btn-back\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Next\"\n customClass=\"cqa-api-edit-step-actions-btn-next\" (clicked)=\"onNext()\">\n </cqa-button>\n </ng-container>\n <ng-container *ngSwitchCase=\"3\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Back\"\n customClass=\"cqa-api-edit-step-actions-btn-back\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Create\"\n customClass=\"cqa-api-edit-step-actions-btn-create\" (clicked)=\"onCreate()\">\n </cqa-button>\n </ng-container>\n </ng-container>\n </div>\n</div>", components: [{ type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i2.NgSwitchDefault, selector: "[ngSwitchDefault]" }], changeDetection: i0.ChangeDetectionStrategy.Default });
|
|
21290
|
+
ApiEditStepComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.4.0", type: ApiEditStepComponent, selector: "cqa-api-edit-step", inputs: { initialMethod: "initialMethod", initialEnvironment: "initialEnvironment", initialStep: "initialStep", initialUrl: "initialUrl", initialPayloadTab: "initialPayloadTab", initialHeaders: "initialHeaders", initialResponsePreview: "initialResponsePreview", initialVariableName: "initialVariableName", editMode: "editMode", httpMethodOptions: "httpMethodOptions", environmentOptions: "environmentOptions", authTypeOptions: "authTypeOptions", initialAuthType: "initialAuthType", formatOptions: "formatOptions", initialFormat: "initialFormat", headerNameOptions: "headerNameOptions", verificationOptions: "verificationOptions", verificationDataTypeOptions: "verificationDataTypeOptions", statusVerificationOptions: "statusVerificationOptions" }, outputs: { importCurl: "importCurl", importCurlCancel: "importCurlCancel", sendRequest: "sendRequest", back: "back", cancel: "cancel", next: "next", create: "create", headersChange: "headersChange" }, host: { classAttribute: "cqa-ui-root" }, viewQueries: [{ propertyName: "payloadEditorWithLinesRef", first: true, predicate: ["payloadEditorWithLinesRef"], descendants: true }, { propertyName: "payloadTextareaRef", first: true, predicate: ["payloadTextareaRef"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"cqa-api-edit-step-container cqa-bg-[#ffffff] cqa-flex cqa-flex-col cqa-w-full cqa-h-full cqa-p-[16px] cqa-gap-[12px] cqa-overflow-y-auto cqa-overflow-x-hidden cqa-box-border\">\n\n <h2 class=\"cqa-api-edit-step-title cqa-font-inter cqa-text-[12px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal cqa-text-[#000000] cqa-m-0\">\n {{ editMode ? 'Update API Test Step' : 'Create API Test Step' }}\n </h2>\n\n <div class=\"cqa-api-edit-step-indicator cqa-flex cqa-items-center cqa-gap-0 cqa-max-[767px]:cqa-flex-wrap cqa-max-[767px]:cqa-gap-2 cqa-max-[767px]:cqa-justify-start\"\n [class.cqa-justify-start]=\"stepLabels.length === 1\"\n [class.cqa-justify-between]=\"stepLabels.length !== 1\">\n <ng-container *ngFor=\"let step of stepLabels; let i = index\">\n <cqa-button type=\"button\" variant=\"text\"\n customClass=\"cqa-api-edit-step-indicator-item cqa-api-edit-step-indicator-item--clickable cqa-flex cqa-items-center cqa-gap-[10px] cqa-cursor-pointer cqa-border-none cqa-p-0 cqa-font-inherit cqa-text-inherit cqa-text-left !cqa-bg-transparent\"\n [attr.aria-label]=\"'Step ' + step.index + ': ' + step.label\" [attr.aria-pressed]=\"step.index === currentStep\"\n (clicked)=\"setStep(step.index)\">\n <span class=\"cqa-api-edit-step-indicator-circle cqa-w-8 cqa-h-8 cqa-rounded-full cqa-inline-flex cqa-items-center cqa-justify-center cqa-text-sm cqa-font-medium cqa-leading-none cqa-border-none cqa-shrink-0\"\n [ngClass]=\"step.index === currentStep ? 'cqa-bg-[#4F46E5] cqa-text-white' : 'cqa-bg-[#E0E0E0] cqa-text-[#666666]'\">\n {{ step.index }}\n </span>\n <span class=\"cqa-api-edit-step-indicator-label cqa-text-sm cqa-leading-[18px] cqa-font-normal cqa-max-[767px]:cqa-text-xs\"\n [ngClass]=\"step.index === currentStep ? 'cqa-text-[#4F46E5]' : 'cqa-text-[#666666]'\">\n {{ step.label }}\n </span>\n <div *ngIf=\"i < stepLabels.length - 1\" class=\"cqa-api-edit-step-indicator-line cqa-w-[96px] cqa-h-[2px] cqa-bg-[#E0E0E0] cqa-my-0 cqa-mx-[6px] cqa-shrink-0 cqa-self-center cqa-max-[767px]:cqa-w-[24px] cqa-max-[767px]:cqa-mx-1\" aria-hidden=\"true\"></div>\n </cqa-button>\n </ng-container>\n </div>\n\n <!-- Step content viewport: only the active step body is shown (*ngIf) -->\n <div class=\"cqa-api-edit-step-viewport cqa-w-full\">\n <!-- Step 1: Environment, request, body, response -->\n <div *ngIf=\"currentStep === 1\" class=\"cqa-api-edit-step-panel cqa-flex cqa-flex-col cqa-gap-6 cqa-box-border cqa-w-full\">\n <!-- Environment row: new line, select aligned right -->\n <div class=\"cqa-api-edit-step-environment-row cqa-flex cqa-justify-end cqa-items-center\">\n <cqa-dynamic-select *ngIf=\"environmentForm\" [form]=\"environmentForm\" [config]=\"environmentSelectConfig\"\n class=\"cqa-api-edit-step-environment-select cqa-shrink-0 cqa-w-auto cqa-min-w-[315px] cqa-max-w-[315px] cqa-max-[767px]:cqa-min-w-0 cqa-max-[767px]:cqa-max-w-full cqa-max-[767px]:cqa-w-full [&_.mat-form-field-wrapper]:cqa-pb-0\" aria-label=\"Environment\"\n (selectionChange)=\"onEnvironmentSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Request row: method, URL, buttons -->\n <div class=\"cqa-api-edit-step-request-row cqa-flex cqa-items-center cqa-gap-3 cqa-flex-wrap cqa-max-[767px]:cqa-flex-col cqa-max-[767px]:cqa-items-stretch cqa-max-[767px]:cqa-gap-2.5\">\n <cqa-dynamic-select *ngIf=\"methodForm\" [form]=\"methodForm\" [config]=\"methodSelectConfig\"\n class=\"cqa-api-edit-step-method-select cqa-shrink-0 cqa-w-auto cqa-min-w-[152px] cqa-max-w-[152px] cqa-max-[767px]:cqa-min-w-0 cqa-max-[767px]:cqa-max-w-full cqa-max-[767px]:cqa-w-full\" aria-label=\"HTTP method\"\n (selectionChange)=\"onMethodSelectionChange($event)\">\n </cqa-dynamic-select>\n <div class=\"cqa-api-edit-step-url-wrap cqa-flex-1 cqa-min-w-[200px] cqa-max-[767px]:cqa-min-w-0 cqa-max-[767px]:cqa-w-full [&_cqa-custom-input_.cqa-relative_input]:cqa-h-[40px] [&_cqa-custom-input_.cqa-relative_input]:cqa-bg-white [&_cqa-custom-input_.cqa-relative_input]:cqa-border [&_cqa-custom-input_.cqa-relative_input]:cqa-border-solid [&_cqa-custom-input_.cqa-relative_input]:cqa-border-[#D1D5DB] [&_cqa-custom-input_.cqa-relative_input]:cqa-rounded-md [&_cqa-custom-input_.cqa-relative_input]:cqa-text-sm [&_cqa-custom-input_.cqa-relative_input]:cqa-text-[#374151]\">\n <cqa-custom-input [(value)]=\"url\" [label]=\"''\" placeholder=\"\" [fullWidth]=\"true\" size=\"md\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-trigger cqa-contents cqa-max-[767px]:cqa-w-full cqa-max-[767px]:!cqa-flex\" (click)=\"openImportCurlPanel()\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Import API cURL\"\n customClass=\"cqa-api-edit-step-btn-outline !cqa-bg-white !cqa-border !cqa-border-solid !cqa-border-[#6B7280] cqa-text-[#414146] cqa-font-inter cqa-text-[14px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal hover:!cqa-bg-[#F9FAFB] hover:!cqa-text-[#414146] cqa-max-[767px]:cqa-w-full\">\n </cqa-button>\n </div>\n <cqa-button variant=\"filled\" btnSize=\"lg\" text=\"Send Request\" (clicked)=\"onSendRequest()\"\n customClass=\"cqa-api-edit-step-btn-primary cqa-font-inter cqa-text-[14px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal !cqa-bg-[#3F43EE] cqa-text-[#FBFCFF] !cqa-border-none cqa-py-2.5 cqa-px-6 cqa-gap-2 cqa-rounded-lg cqa-min-h-[37px] cqa-box-border hover:!cqa-bg-[#1B1FEB] cqa-max-[767px]:cqa-w-full\">\n </cqa-button>\n </div>\n\n\n\n <!-- Body content: header section (default) OR import cURL section -->\n <ng-container *ngIf=\"bodyView === 'import-curl'\">\n <div class=\"cqa-api-edit-step-import-curl-panel cqa-flex cqa-flex-col cqa-bg-white cqa-rounded-lg cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-shadow-[0_1px_3px_rgba(0,0,0,0.08)] cqa-overflow-hidden\">\n <div class=\"cqa-api-edit-step-import-curl-header cqa-flex cqa-items-center cqa-justify-between cqa-py-3 cqa-px-5 cqa-border-b cqa-border-solid cqa-border-[#E2E8F0] cqa-bg-[#F9FAFB] cqa-rounded-t-lg cqa-max-[767px]:cqa-px-4\">\n <h3 class=\"cqa-api-edit-step-import-curl-title cqa-m-0 cqa-text-xs cqa-font-bold cqa-leading-[18px] cqa-text-[#374151]\">Import API cURL</h3>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-separator cqa-h-px cqa-bg-[#E2E8F0] cqa-my-0 cqa-mx-5\"></div>\n <div class=\"cqa-api-edit-step-import-curl-body\">\n <cqa-custom-textarea [value]=\"importCurlControl.value\"\n (valueChange)=\"importCurlControl.setValue($event)\"\n placeholder=\"Paste your cURL command here (e.g., curl -X POST https://api.example.com/users)\"\n [fullWidth]=\"true\" [rows]=\"8\" resize=\"vertical\" size=\"md\"\n class=\"cqa-api-edit-step-import-curl-textarea\">\n </cqa-custom-textarea>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-footer\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Cancel\"\n customClass=\"cqa-api-edit-step-import-curl-btn-cancel\" (clicked)=\"onCancelImportCurl()\"></cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Import\"\n customClass=\"cqa-api-edit-step-import-curl-btn-import\" (clicked)=\"onImportCurlConfirm()\"></cqa-button>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"bodyView === 'headers'\">\n <div class=\"cqa-api-edit-step-tabs-wrapper\">\n <div class=\"cqa-api-edit-step-tabs\">\n <cqa-button *ngFor=\"let tab of payloadTabs\" type=\"button\" variant=\"text\" [text]=\"tab.label\"\n [customClass]=\"'cqa-api-edit-step-tab' + (activePayloadTab === tab.value ? ' cqa-api-edit-step-tab--active' : '') + (isMethodWithoutBody && (tab.value === 'body' || tab.value === 'params') ? ' cqa-api-edit-step-tab--disabled' : '')\"\n [disabled]=\"isMethodWithoutBody && (tab.value === 'body' || tab.value === 'params')\"\n (clicked)=\"setPayloadTab(tab.value)\">\n </cqa-button>\n </div>\n\n <!-- Payload content (Authorization) -->\n <div *ngIf=\"activePayloadTab === 'authorization'\" class=\"cqa-api-edit-step-payload\"\n [attr.style]=\"'padding: 20px; min-height: 200px;'\">\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 20px;'\">\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 8px; width: fit-content;'\">\n <span [attr.style]=\"'font-size: 11px; font-weight: 600; letter-spacing: 0.02em; color: #6B7280; text-transform: uppercase; line-height: 1.25;'\">AUTH TYPE</span>\n <cqa-dynamic-select *ngIf=\"authTypeForm\" [form]=\"authTypeForm\" [config]=\"authTypeSelectConfig\"\n class=\"cqa-api-edit-step-auth-type-select\" aria-label=\"Auth type\"\n [attr.style]=\"'min-width: 160px;'\">\n </cqa-dynamic-select>\n </div>\n <!-- No Auth: centered message -->\n <div *ngIf=\"selectedAuthType === 'no-auth'\"\n [attr.style]=\"'flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-width: 0; text-align: center;'\">\n <div aria-hidden=\"true\"\n [attr.style]=\"'width: 48px; height: 48px; border-radius: 10px; background: #F3F4F6; display: flex; align-items: center; justify-content: center; flex-shrink: 0;'\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" style=\"display: block;\">\n <rect x=\"5\" y=\"11\" width=\"14\" height=\"2\" rx=\"1\" fill=\"#9CA3AF\"/>\n </svg>\n </div>\n <span [attr.style]=\"'font-size: 16px; font-weight: 600; color: #374151; line-height: 1.25;'\">No Auth</span>\n <div [attr.style]=\"'display: flex; align-items: center; justify-content: center; gap: 6px; flex-wrap: wrap;'\">\n <span [attr.style]=\"'font-size: 14px; font-weight: 400; color: #9CA3AF; line-height: 1.4;'\">This request does not use any authorization.</span>\n <span role=\"img\" aria-label=\"More information\" title=\"This request does not use any authorization.\"\n [attr.style]=\"'display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; color: #9CA3AF; flex-shrink: 0;'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" style=\"display: block;\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"#9CA3AF\" stroke-width=\"1.5\" fill=\"none\"/>\n <path d=\"M8 7v4M8 5v.5\" stroke=\"#9CA3AF\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n </div>\n </div>\n <!-- Bearer Token: Token label + textarea -->\n <div *ngIf=\"selectedAuthType === 'bearer'\"\n [attr.style]=\"'flex: 1; display: flex; flex-direction: column; gap: 10px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Token</span>\n <cqa-custom-textarea [(value)]=\"bearerToken\"\n placeholder=\"Enter bearer token\"\n [fullWidth]=\"true\" [rows]=\"6\" resize=\"vertical\" size=\"md\"\n class=\"cqa-api-edit-step-auth-token-textarea\" ariaLabel=\"Bearer token\">\n </cqa-custom-textarea>\n </div>\n <!-- OAuth 2.0: Grant Type, Access Token URL, Client ID, Client Secret, Scope, Client Authentication -->\n <div *ngIf=\"selectedAuthType === 'oauth2' && oauth2Form\"\n class=\"cqa-api-edit-step-oauth2-grid\"\n [attr.style]=\"'display: grid; grid-template-columns: 1fr 1fr; gap: 16px 24px; width: 100%;'\">\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Grant Type</span>\n <cqa-dynamic-select *ngIf=\"oauth2Form\" [form]=\"oauth2Form\" [config]=\"oauth2GrantTypeSelectConfig\"\n class=\"cqa-api-edit-step-auth-oauth-select\" aria-label=\"OAuth grant type\"\n [attr.style]=\"'min-width: 0; width: 100%;'\">\n </cqa-dynamic-select>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">OAuth grant type</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Access Token URL</span>\n <cqa-custom-input [value]=\"oauth2Form.get('accessTokenUrl')?.value\"\n (valueChange)=\"oauth2Form.get('accessTokenUrl')?.setValue($event)\"\n [label]=\"''\" placeholder=\"Enter OAuth token endpoint\" [fullWidth]=\"true\" size=\"md\"\n ariaLabel=\"Access Token URL\">\n </cqa-custom-input>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">OAuth token endpoint</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Client ID</span>\n <cqa-custom-input [value]=\"oauth2Form.get('clientId')?.value\"\n (valueChange)=\"oauth2Form.get('clientId')?.setValue($event)\"\n [label]=\"''\" placeholder=\"Enter OAuth client identifier\" [fullWidth]=\"true\" size=\"md\"\n ariaLabel=\"Client ID\">\n </cqa-custom-input>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">OAuth client identifier</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Client Secret</span>\n <cqa-custom-input [value]=\"oauth2Form.get('clientSecret')?.value\"\n (valueChange)=\"oauth2Form.get('clientSecret')?.setValue($event)\"\n type=\"password\" [label]=\"''\" placeholder=\"Enter OAuth client secret\" [fullWidth]=\"true\" size=\"md\"\n ariaLabel=\"Client Secret\">\n </cqa-custom-input>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">OAuth client secret</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Scope</span>\n <cqa-custom-input [value]=\"oauth2Form.get('scope')?.value\"\n (valueChange)=\"oauth2Form.get('scope')?.setValue($event)\"\n [label]=\"''\" placeholder=\"Enter space-separated scopes\" [fullWidth]=\"true\" size=\"md\"\n ariaLabel=\"Scope\">\n </cqa-custom-input>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">Space-separated scopes</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Client Authentication</span>\n <cqa-dynamic-select *ngIf=\"oauth2Form\" [form]=\"oauth2Form\" [config]=\"oauth2ClientAuthSelectConfig\"\n class=\"cqa-api-edit-step-auth-oauth-select\" aria-label=\"Client authentication method\"\n [attr.style]=\"'min-width: 0; width: 100%;'\">\n </cqa-dynamic-select>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">Client authentication method</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Payload content (Headers) -->\n <div *ngIf=\"activePayloadTab === 'headers'\" class=\"cqa-api-edit-step-payload\">\n <div class=\"cqa-api-edit-step-headers-grid\">\n <span class=\"cqa-api-edit-step-headers-label\">Header Name</span>\n <span class=\"cqa-api-edit-step-headers-label\">Header Value</span>\n <span class=\"cqa-api-edit-step-headers-label cqa-api-edit-step-headers-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of headerRows; let i = index; trackBy: trackByHeader\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-header-row\">\n <cqa-dynamic-select [form]=\"row\" [config]=\"headerNameSelectConfig\"\n (addCustomValue)=\"onHeaderNameAddCustomValue($event, row)\"\n class=\"cqa-api-edit-step-header-type-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-header-value-input\" ariaLabel=\"Header value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-header-delete'\"\n [tooltip]=\"'Remove header'\" (clicked)=\"removeHeader(i)\">\n <svg class=\"cqa-api-edit-step-header-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-add-header-wrap\">\n <cqa-button type=\"button\" variant=\"text\" text=\"+ Add Header\"\n [customClass]=\"'cqa-api-edit-step-add-header-link'\" (clicked)=\"addHeader()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Payload content (Params): Key\u2013Value table with add/delete rows -->\n <div *ngIf=\"activePayloadTab === 'params'\" class=\"cqa-api-edit-step-payload\">\n <div class=\"cqa-api-edit-step-key-value-grid cqa-api-edit-step-key-value-header\">\n <span class=\"cqa-api-edit-step-key-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-value-label cqa-api-edit-step-key-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of paramsRows; let i = index; trackBy: trackByParams\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeParamsRow(i)\">\n <svg class=\"cqa-api-edit-step-key-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-value-add-btn\" (clicked)=\"addParamsRow()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Payload content (Body only): type, format, text area, Back/Next -->\n <div *ngIf=\"activePayloadTab === 'body'\"\n class=\"cqa-api-edit-step-payload cqa-api-edit-step-payload-editor\">\n <div class=\"cqa-api-edit-step-payload-type-row\">\n <span class=\"cqa-api-edit-step-payload-type-label\">Type</span>\n <div class=\"cqa-api-edit-step-payload-type-radios\">\n <cqa-segment-control [value]=\"payloadType\" [segments]=\"payloadTypeSegments\"\n (valueChange)=\"onPayloadTypeChange($event)\"\n class=\"cqa-api-edit-step-payload-type-segment\">\n </cqa-segment-control>\n </div>\n <div *ngIf=\"payloadType === 'raw'\" class=\"cqa-api-edit-step-payload-format-wrap\">\n <span class=\"cqa-api-edit-step-payload-format-label\">Format:</span>\n <cqa-dynamic-select *ngIf=\"payloadFormatForm\" [form]=\"payloadFormatForm\"\n [config]=\"payloadFormatSelectConfig\" class=\"cqa-api-edit-step-payload-format-select\"\n aria-label=\"Format\">\n </cqa-dynamic-select>\n </div>\n </div>\n <!-- Raw: text area with line numbers (Postman-style payload body) -->\n <div *ngIf=\"payloadType === 'raw'\" class=\"cqa-api-edit-step-payload-body\" #payloadEditorWithLinesRef>\n <div class=\"cqa-api-edit-step-payload-editor-with-lines\">\n <div class=\"cqa-api-edit-step-payload-line-numbers\" aria-hidden=\"true\">\n <span *ngFor=\"let n of payloadLineNumbers\" class=\"cqa-api-edit-step-payload-line-num\">\n <span *ngIf=\"payloadJsonError && payloadJsonError.line === n\"\n class=\"cqa-api-edit-step-payload-line-error-icon\" [title]=\"payloadJsonErrorTooltip\"\n aria-label=\"Parse error on this line\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"6\" fill=\"#EF4444\"/>\n <path d=\"M4 4l6 6M10 4l-6 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-api-edit-step-payload-line-num-text\">{{ n }}</span>\n </span>\n </div>\n <div class=\"cqa-api-edit-step-payload-textarea-cell\">\n <div class=\"cqa-api-edit-step-payload-textarea cqa-w-full cqa-flex cqa-flex-col cqa-min-h-0\"\n [ngClass]=\"{'cqa-api-edit-step-payload-textarea--error': payloadJsonError}\">\n <textarea #payloadTextareaRef\n class=\"cqa-api-edit-step-payload-textarea-input cqa-w-full cqa-outline-none cqa-box-border\"\n [ngClass]=\"{'cqa-api-edit-step-payload-textarea-input--error': payloadJsonError}\"\n [value]=\"payloadText\"\n placeholder=\"\"\n [attr.aria-label]=\"'Payload'\"\n [attr.aria-invalid]=\"!!payloadJsonError\"\n (input)=\"onPayloadInput($event)\"\n (keydown)=\"onPayloadKeydown($event)\">\n </textarea>\n </div>\n </div>\n </div>\n <p *ngIf=\"payloadJsonError\" class=\"cqa-api-edit-step-payload-json-error-msg\">\n Invalid JSON format. Please check your syntax.\n </p>\n </div>\n\n <!-- x-www-form-urlencoded: Key\u2013Value rows, add/remove dynamically -->\n <div *ngIf=\"payloadType === 'x-www-form-urlencoded'\" class=\"cqa-api-edit-step-key-value\">\n <div class=\"cqa-api-edit-step-key-value-grid cqa-api-edit-step-key-value-header\">\n <span class=\"cqa-api-edit-step-key-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-value-label cqa-api-edit-step-key-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of keyValueRows; let i = index; trackBy: trackByKeyValue\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeKeyValueRow(i)\">\n <svg class=\"cqa-api-edit-step-key-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-value-add-btn\" (clicked)=\"addKeyValueRow()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Form Data: Key\u2013Type\u2013Value rows; Type is a dropdown (Text/File), add/remove dynamically -->\n <div *ngIf=\"payloadType === 'form-data'\" class=\"cqa-api-edit-step-key-type-value\">\n <div class=\"cqa-api-edit-step-key-type-value-header\">\n <span class=\"cqa-api-edit-step-key-type-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-type-value-label\">Type</span>\n <span class=\"cqa-api-edit-step-key-type-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-type-value-label cqa-api-edit-step-key-type-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of keyTypeValueRows; let i = index; trackBy: trackByKeyTypeValue\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-type-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-type-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"row\" [config]=\"keyTypeValueTypeSelectConfig\"\n class=\"cqa-api-edit-step-key-type-value-type-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-type-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-type-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeKeyTypeValueRow(i)\">\n <svg class=\"cqa-api-edit-step-key-type-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-type-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-type-value-add-btn\" (clicked)=\"addKeyTypeValueRow()\">\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n\n </div>\n <!-- Step 2: Variable Name: input, validation, Back / Next -->\n <div *ngIf=\"currentStep === 2\" class=\"cqa-api-edit-step-panel cqa-flex cqa-flex-col cqa-gap-6 cqa-box-border cqa-w-full\">\n <div class=\"cqa-api-edit-step-variable-section\">\n <div class=\"cqa-api-edit-step-variable-input-wrap\">\n <cqa-custom-input [(value)]=\"variableName\" [label]=\"''\" placeholder=\"Variable Name\" [fullWidth]=\"true\"\n size=\"md\" (valueChange)=\"onVariableNameChange()\" aria-label=\"Variable Name\">\n </cqa-custom-input>\n </div>\n <p *ngIf=\"variableNameError\" class=\"cqa-api-edit-step-variable-error\" role=\"alert\">{{ variableNameError }}</p>\n </div>\n </div>\n <!-- Step 3: Response Body / Status tabs -->\n <div *ngIf=\"currentStep === 3\" class=\"cqa-api-edit-step-panel cqa-flex cqa-flex-col cqa-gap-6 cqa-box-border cqa-w-full\">\n <div class=\"cqa-api-edit-step-tabs-wrapper\">\n <div class=\"cqa-api-edit-step-tabs\">\n <cqa-button *ngFor=\"let tab of responseVerificationTabs\" type=\"button\" variant=\"text\" [text]=\"tab.label\"\n [customClass]=\"'cqa-api-edit-step-tab' + (activeResponseVerificationTab === tab.value ? ' cqa-api-edit-step-tab--active' : '')\"\n (clicked)=\"setResponseVerificationTab(tab.value)\">\n </cqa-button>\n </div>\n\n <!-- Response Body tab content: verification grid -->\n <div *ngIf=\"activeResponseVerificationTab === 'response-body'\" class=\"cqa-api-edit-step-step3-content\">\n <div class=\"cqa-api-edit-step-verification-header-row\">\n <span></span>\n <cqa-button type=\"button\" variant=\"text\" text=\"Add Verification\"\n customClass=\"cqa-api-edit-step-verification-add-link\" (clicked)=\"addVerificationRow()\">\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-verification\">\n <div class=\"cqa-api-edit-step-verification-grid cqa-api-edit-step-verification-grid-header\">\n <span class=\"cqa-api-edit-step-verification-label\">S.no</span>\n <span class=\"cqa-api-edit-step-verification-label\">JSON Path</span>\n <span class=\"cqa-api-edit-step-verification-label\">Verification</span>\n <span class=\"cqa-api-edit-step-verification-label\">Data Type</span>\n <span class=\"cqa-api-edit-step-verification-label\">Expected Value</span>\n <span class=\"cqa-api-edit-step-verification-label cqa-api-edit-step-verification-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of verificationRows; let i = index; trackBy: trackByVerification\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-verification-row\">\n <span class=\"cqa-api-edit-step-verification-sno\">{{ i + 1 }}</span>\n <cqa-custom-input [value]=\"row.get('jsonPath')?.value ?? ''\"\n (valueChange)=\"row.get('jsonPath')?.setValue($event)\" placeholder=\"Json Path\" [fullWidth]=\"true\"\n size=\"sm\" class=\"cqa-api-edit-step-verification-input\" ariaLabel=\"JSON Path\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"row\" [config]=\"verificationSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-dynamic-select [form]=\"row\" [config]=\"verificationDataTypeSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-w-full\"\n (selectionChange)=\"onVerificationDataTypeChange(row, $event)\">\n </cqa-dynamic-select>\n <!-- Expected Value: text for String/Array/Object, number for Number, dropdown for Boolean -->\n <ng-container [ngSwitch]=\"row.get('dataType')?.value\">\n <cqa-dynamic-select *ngSwitchCase=\"'boolean'\" [form]=\"row\"\n [config]=\"verificationExpectedValueBooleanSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-api-edit-step-verification-expected-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input *ngSwitchCase=\"'number'\" [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\" placeholder=\"Expected Value (number)\"\n type=\"number\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-verification-input cqa-api-edit-step-verification-expected-number\"\n ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n <cqa-custom-input *ngSwitchDefault [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\"\n placeholder=\"Expected Value in String\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-verification-input\" ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n </ng-container>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-verification-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeVerificationRow(i)\">\n <svg class=\"cqa-api-edit-step-verification-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n </div>\n </div>\n\n <!-- Status tab content: S.no, Verification dropdown, Expected Value, add/remove rows -->\n <div *ngIf=\"activeResponseVerificationTab === 'status'\" class=\"cqa-api-edit-step-step3-content\">\n <div class=\"cqa-api-edit-step-verification-header-row\">\n <span></span>\n <cqa-button type=\"button\" variant=\"text\" text=\"Add Verification\"\n customClass=\"cqa-api-edit-step-verification-add-link\" (clicked)=\"addStatusVerificationRow()\">\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-status-verification\">\n <div class=\"cqa-api-edit-step-status-verification-header\">\n <span class=\"cqa-api-edit-step-verification-label\">S.no</span>\n <span class=\"cqa-api-edit-step-verification-label\">Verification</span>\n <span class=\"cqa-api-edit-step-verification-label\">Expected Value</span>\n <span class=\"cqa-api-edit-step-verification-label cqa-api-edit-step-verification-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of statusVerificationRows; let i = index; trackBy: trackByStatusVerification\"\n [formGroup]=\"row\" class=\"cqa-api-edit-step-status-verification-row\">\n <span class=\"cqa-api-edit-step-verification-sno\">{{ i + 1 }}</span>\n <cqa-dynamic-select [form]=\"row\" [config]=\"statusVerificationSelectConfig\"\n class=\"cqa-api-edit-step-status-verification-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\" placeholder=\"Expected Value\"\n type=\"number\" [fullWidth]=\"true\" size=\"sm\" class=\"cqa-api-edit-step-verification-input\"\n ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-verification-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeStatusVerificationRow(i)\">\n <svg class=\"cqa-api-edit-step-verification-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Response Preview -->\n <div class=\"cqa-api-edit-step-response\">\n <h3 class=\"cqa-api-edit-step-response-title cqa-text-[14px] cqa-font-bold cqa-leading-[20px] cqa-text-[#111827] cqa-m-0 cqa-mb-[12px] cqa-shrink-0\">Response Preview</h3>\n <pre class=\"cqa-api-edit-step-response-content\">{{ responsePreview }}</pre>\n </div>\n\n <!-- Step actions: one row, full width. Step 1: Cancel + Next; Step 2: Back + Next; Step 3: Back + Create -->\n <div class=\"cqa-api-edit-step-actions\">\n <ng-container [ngSwitch]=\"currentStep\">\n <ng-container *ngSwitchCase=\"1\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Cancel\"\n customClass=\"cqa-api-edit-step-actions-btn-cancel\" (clicked)=\"onCancel()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Next\"\n customClass=\"cqa-api-edit-step-actions-btn-next\" (clicked)=\"onNext()\">\n </cqa-button>\n </ng-container>\n <ng-container *ngSwitchCase=\"2\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Back\"\n customClass=\"cqa-api-edit-step-actions-btn-back\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Next\"\n customClass=\"cqa-api-edit-step-actions-btn-next\" (clicked)=\"onNext()\">\n </cqa-button>\n </ng-container>\n <ng-container *ngSwitchCase=\"3\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Back\"\n customClass=\"cqa-api-edit-step-actions-btn-back\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" [text]=\"editMode ? 'Update' : 'Create'\"\n customClass=\"cqa-api-edit-step-actions-btn-create\" (clicked)=\"onCreate()\">\n </cqa-button>\n </ng-container>\n </ng-container>\n </div>\n</div>", components: [{ type: ButtonComponent, selector: "cqa-button", inputs: ["variant", "btnSize", "disabled", "icon", "iconPosition", "fullWidth", "iconColor", "type", "text", "customClass", "inlineStyles", "tooltip", "tooltipPosition"], outputs: ["clicked"] }, { type: DynamicSelectFieldComponent, selector: "cqa-dynamic-select", inputs: ["form", "config"], outputs: ["selectionChange", "selectClick", "searchChange", "loadMore", "addCustomValue"] }, { type: CustomInputComponent, selector: "cqa-custom-input", inputs: ["label", "type", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "inputInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused", "enterPressed"] }, { type: CustomTextareaComponent, selector: "cqa-custom-textarea", inputs: ["label", "placeholder", "value", "disabled", "errors", "required", "ariaLabel", "size", "fullWidth", "maxLength", "showCharCount", "rows", "cols", "resize", "textareaInlineStyle", "labelInlineStyle"], outputs: ["valueChange", "blurred", "focused"] }, { type: SegmentControlComponent, selector: "cqa-segment-control", inputs: ["segments", "value", "disabled", "containerBgColor"], outputs: ["valueChange"] }], directives: [{ type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i2.NgSwitchDefault, selector: "[ngSwitchDefault]" }], changeDetection: i0.ChangeDetectionStrategy.Default });
|
|
20709
21291
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImport: i0, type: ApiEditStepComponent, decorators: [{
|
|
20710
21292
|
type: Component,
|
|
20711
|
-
args: [{ selector: 'cqa-api-edit-step', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.Default, template: "<div class=\"cqa-api-edit-step-container\">\n <!-- Title -->\n <h2\n class=\"cqa-api-edit-step-title cqa-font-inter cqa-text-[12px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal cqa-text-[#000000]\">\n Create API Test Step</h2>\n\n <!-- Step indicator: all three steps visible, active step highlighted (Postman-style) -->\n <div class=\"cqa-api-edit-step-indicator\">\n <ng-container *ngFor=\"let step of stepLabels; let i = index\">\n <cqa-button type=\"button\" variant=\"text\"\n customClass=\"cqa-api-edit-step-indicator-item cqa-api-edit-step-indicator-item--clickable\"\n [attr.aria-label]=\"'Step ' + step.index + ': ' + step.label\" [attr.aria-pressed]=\"step.index === currentStep\"\n (clicked)=\"setStep(step.index)\">\n <span class=\"cqa-api-edit-step-indicator-circle\"\n [class.cqa-api-edit-step-indicator-circle--active]=\"step.index === currentStep\">\n {{ step.index }}\n </span>\n <span class=\"cqa-api-edit-step-indicator-label\"\n [class.cqa-api-edit-step-indicator-label--active]=\"step.index === currentStep\">\n {{ step.label }}\n </span>\n <div *ngIf=\"i < stepLabels.length - 1\" class=\"cqa-api-edit-step-indicator-line\" aria-hidden=\"true\"></div>\n </cqa-button>\n </ng-container>\n </div>\n\n <!-- Step content viewport: smooth slide between steps -->\n <div class=\"cqa-api-edit-step-viewport\">\n <div class=\"cqa-api-edit-step-strip\" [style.transform]=\"'translateX(' + stripTranslatePercent + '%)'\">\n <!-- Step 1: Environment, request, body, response -->\n <div class=\"cqa-api-edit-step-panel\">\n <!-- Environment row: new line, select aligned right -->\n <div class=\"cqa-api-edit-step-environment-row\">\n <cqa-dynamic-select *ngIf=\"environmentForm\" [form]=\"environmentForm\" [config]=\"environmentSelectConfig\"\n class=\"cqa-api-edit-step-environment-select\" aria-label=\"Environment\"\n (selectionChange)=\"onEnvironmentSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Request row: method, URL, buttons -->\n <div class=\"cqa-api-edit-step-request-row\">\n <cqa-dynamic-select *ngIf=\"methodForm\" [form]=\"methodForm\" [config]=\"methodSelectConfig\"\n class=\"cqa-api-edit-step-method-select\" aria-label=\"HTTP method\"\n (selectionChange)=\"onMethodSelectionChange($event)\">\n </cqa-dynamic-select>\n <div class=\"cqa-api-edit-step-url-wrap\">\n <cqa-custom-input [(value)]=\"url\" [label]=\"''\" placeholder=\"\" [fullWidth]=\"true\" size=\"md\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-trigger\" style=\"display: contents\" (click)=\"openImportCurlPanel()\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Import API cURL\"\n customClass=\"cqa-api-edit-step-btn-outline cqa-font-inter cqa-text-[14px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal cqa-text-[#414146]\">\n </cqa-button>\n </div>\n <cqa-button variant=\"filled\" btnSize=\"lg\" text=\"Send Request\" (clicked)=\"onSendRequest()\"\n customClass=\"cqa-api-edit-step-btn-primary cqa-font-inter cqa-text-[14px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal cqa-text-[#FBFCFF]\">\n </cqa-button>\n </div>\n\n\n\n <!-- Body content: header section (default) OR import cURL section -->\n <ng-container *ngIf=\"bodyView === 'import-curl'\">\n <div class=\"cqa-api-edit-step-import-curl-panel\">\n <div class=\"cqa-api-edit-step-import-curl-header\">\n <h3 class=\"cqa-api-edit-step-import-curl-title\">Import API cURL</h3>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-separator\"></div>\n <div class=\"cqa-api-edit-step-import-curl-body\">\n <cqa-custom-textarea [value]=\"importCurlControl.value\"\n (valueChange)=\"importCurlControl.setValue($event)\"\n placeholder=\"Paste your cURL command here (e.g., curl -X POST https://api.example.com/users)\"\n [fullWidth]=\"true\" [rows]=\"8\" resize=\"vertical\" size=\"md\"\n class=\"cqa-api-edit-step-import-curl-textarea\">\n </cqa-custom-textarea>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-footer\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Cancel\"\n customClass=\"cqa-api-edit-step-import-curl-btn-cancel\" (clicked)=\"onCancelImportCurl()\"></cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Import\"\n customClass=\"cqa-api-edit-step-import-curl-btn-import\" (clicked)=\"onImportCurlConfirm()\"></cqa-button>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"bodyView === 'headers'\">\n <div class=\"cqa-api-edit-step-tabs-wrapper\">\n <div class=\"cqa-api-edit-step-tabs\">\n <cqa-button *ngFor=\"let tab of payloadTabs\" type=\"button\" variant=\"text\" [text]=\"tab.label\"\n [customClass]=\"'cqa-api-edit-step-tab' + (activePayloadTab === tab.value ? ' cqa-api-edit-step-tab--active' : '') + (isMethodWithoutBody && tab.value !== 'headers' ? ' cqa-api-edit-step-tab--disabled' : '')\"\n [disabled]=\"isMethodWithoutBody && tab.value !== 'headers'\"\n (clicked)=\"setPayloadTab(tab.value)\">\n </cqa-button>\n </div>\n\n <!-- Payload content (Headers) -->\n <div *ngIf=\"activePayloadTab === 'headers'\" class=\"cqa-api-edit-step-payload\">\n <div class=\"cqa-api-edit-step-headers-grid\">\n <span class=\"cqa-api-edit-step-headers-label\">Header Name</span>\n <span class=\"cqa-api-edit-step-headers-label\">Header Value</span>\n <span class=\"cqa-api-edit-step-headers-label cqa-api-edit-step-headers-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of headerRows; let i = index; trackBy: trackByHeader\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-header-row\">\n <cqa-dynamic-select [form]=\"row\" [config]=\"headerNameSelectConfig\"\n (addCustomValue)=\"onHeaderNameAddCustomValue($event, row)\"\n class=\"cqa-api-edit-step-header-type-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-header-value-input\" ariaLabel=\"Header value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-header-delete'\"\n [tooltip]=\"'Remove header'\" (clicked)=\"removeHeader(i)\">\n <svg class=\"cqa-api-edit-step-header-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-add-header-wrap\">\n <cqa-button type=\"button\" variant=\"text\" text=\"+ Add Header\"\n [customClass]=\"'cqa-api-edit-step-add-header-link'\" (clicked)=\"addHeader()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Payload content (Body only): type, format, text area, Back/Next -->\n <div *ngIf=\"activePayloadTab === 'body'\"\n class=\"cqa-api-edit-step-payload cqa-api-edit-step-payload-editor\">\n <div class=\"cqa-api-edit-step-payload-type-row\">\n <span class=\"cqa-api-edit-step-payload-type-label\">Type</span>\n <div class=\"cqa-api-edit-step-payload-type-radios\">\n <cqa-segment-control [value]=\"payloadType\" [segments]=\"payloadTypeSegments\"\n (valueChange)=\"onPayloadTypeChange($event)\"\n class=\"cqa-api-edit-step-payload-type-segment\">\n </cqa-segment-control>\n </div>\n <div *ngIf=\"payloadType === 'raw'\" class=\"cqa-api-edit-step-payload-format-wrap\">\n <span class=\"cqa-api-edit-step-payload-format-label\">Format:</span>\n <cqa-dynamic-select *ngIf=\"payloadFormatForm\" [form]=\"payloadFormatForm\"\n [config]=\"payloadFormatSelectConfig\" class=\"cqa-api-edit-step-payload-format-select\"\n aria-label=\"Format\">\n </cqa-dynamic-select>\n </div>\n </div>\n <!-- Raw: text area with line numbers (Postman-style payload body) -->\n <div *ngIf=\"payloadType === 'raw'\" class=\"cqa-api-edit-step-payload-body\" #payloadEditorWithLinesRef>\n <div class=\"cqa-api-edit-step-payload-editor-with-lines\">\n <div class=\"cqa-api-edit-step-payload-line-numbers\" aria-hidden=\"true\">\n <span *ngFor=\"let n of payloadLineNumbers\" class=\"cqa-api-edit-step-payload-line-num\">\n <span *ngIf=\"payloadJsonError && payloadJsonError.line === n\"\n class=\"cqa-api-edit-step-payload-line-error-icon\" [title]=\"payloadJsonErrorTooltip\"\n aria-label=\"Parse error on this line\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"6\" fill=\"#EF4444\"/>\n <path d=\"M4 4l6 6M10 4l-6 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-api-edit-step-payload-line-num-text\">{{ n }}</span>\n </span>\n </div>\n <div class=\"cqa-api-edit-step-payload-textarea-cell\">\n <div class=\"cqa-api-edit-step-payload-textarea cqa-w-full cqa-flex cqa-flex-col cqa-min-h-0\"\n [ngClass]=\"{'cqa-api-edit-step-payload-textarea--error': payloadJsonError}\">\n <textarea #payloadTextareaRef\n class=\"cqa-api-edit-step-payload-textarea-input cqa-w-full cqa-resize-y cqa-outline-none cqa-box-border\"\n [ngClass]=\"{'cqa-api-edit-step-payload-textarea-input--error': payloadJsonError}\"\n [value]=\"payloadText\"\n [attr.rows]=\"10\"\n placeholder=\"\"\n [attr.aria-label]=\"'Payload'\"\n [attr.aria-invalid]=\"!!payloadJsonError\"\n (input)=\"onPayloadInput($event)\"\n (keydown)=\"onPayloadKeydown($event)\">\n </textarea>\n </div>\n </div>\n </div>\n <p *ngIf=\"payloadJsonError\" class=\"cqa-api-edit-step-payload-json-error-msg\">\n Invalid JSON format. Please check your syntax.\n </p>\n </div>\n\n <!-- x-www-form-urlencoded: Key\u2013Value rows, add/remove dynamically -->\n <div *ngIf=\"payloadType === 'x-www-form-urlencoded'\" class=\"cqa-api-edit-step-key-value\">\n <div class=\"cqa-api-edit-step-key-value-grid cqa-api-edit-step-key-value-header\">\n <span class=\"cqa-api-edit-step-key-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-value-label cqa-api-edit-step-key-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of keyValueRows; let i = index; trackBy: trackByKeyValue\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeKeyValueRow(i)\">\n <svg class=\"cqa-api-edit-step-key-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-value-add-btn\" (clicked)=\"addKeyValueRow()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Form Data: Key\u2013Type\u2013Value rows; Type is a dropdown (Text/File), add/remove dynamically -->\n <div *ngIf=\"payloadType === 'form-data'\" class=\"cqa-api-edit-step-key-type-value\">\n <div class=\"cqa-api-edit-step-key-type-value-header\">\n <span class=\"cqa-api-edit-step-key-type-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-type-value-label\">Type</span>\n <span class=\"cqa-api-edit-step-key-type-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-type-value-label cqa-api-edit-step-key-type-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of keyTypeValueRows; let i = index; trackBy: trackByKeyTypeValue\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-type-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-type-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"row\" [config]=\"keyTypeValueTypeSelectConfig\"\n class=\"cqa-api-edit-step-key-type-value-type-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-type-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-type-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeKeyTypeValueRow(i)\">\n <svg class=\"cqa-api-edit-step-key-type-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-type-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-type-value-add-btn\" (clicked)=\"addKeyTypeValueRow()\">\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n\n </div>\n <!-- Step 2: Variable Name: input, validation, Back / Next -->\n <div class=\"cqa-api-edit-step-panel\">\n <div class=\"cqa-api-edit-step-variable-section\">\n <div class=\"cqa-api-edit-step-variable-input-wrap\">\n <cqa-custom-input [(value)]=\"variableName\" [label]=\"''\" placeholder=\"Variable Name\" [fullWidth]=\"true\"\n size=\"md\" (valueChange)=\"onVariableNameChange()\" aria-label=\"Variable Name\">\n </cqa-custom-input>\n </div>\n <p *ngIf=\"variableNameError\" class=\"cqa-api-edit-step-variable-error\" role=\"alert\">{{ variableNameError }}</p>\n </div>\n </div>\n <!-- Step 3: Response Body / Status tabs -->\n <div class=\"cqa-api-edit-step-panel\">\n <div class=\"cqa-api-edit-step-tabs-wrapper\">\n <div class=\"cqa-api-edit-step-tabs\">\n <cqa-button *ngFor=\"let tab of responseVerificationTabs\" type=\"button\" variant=\"text\" [text]=\"tab.label\"\n [customClass]=\"'cqa-api-edit-step-tab' + (activeResponseVerificationTab === tab.value ? ' cqa-api-edit-step-tab--active' : '')\"\n (clicked)=\"setResponseVerificationTab(tab.value)\">\n </cqa-button>\n </div>\n\n <!-- Response Body tab content: verification grid -->\n <div *ngIf=\"activeResponseVerificationTab === 'response-body'\" class=\"cqa-api-edit-step-step3-content\">\n <div class=\"cqa-api-edit-step-verification-header-row\">\n <span></span>\n <cqa-button type=\"button\" variant=\"text\" text=\"Add Verification\"\n customClass=\"cqa-api-edit-step-verification-add-link\" (clicked)=\"addVerificationRow()\">\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-verification\">\n <div class=\"cqa-api-edit-step-verification-grid cqa-api-edit-step-verification-grid-header\">\n <span class=\"cqa-api-edit-step-verification-label\">S.no</span>\n <span class=\"cqa-api-edit-step-verification-label\">JSON Path</span>\n <span class=\"cqa-api-edit-step-verification-label\">Verification</span>\n <span class=\"cqa-api-edit-step-verification-label\">Data Type</span>\n <span class=\"cqa-api-edit-step-verification-label\">Expected Value</span>\n <span class=\"cqa-api-edit-step-verification-label cqa-api-edit-step-verification-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of verificationRows; let i = index; trackBy: trackByVerification\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-verification-row\">\n <span class=\"cqa-api-edit-step-verification-sno\">{{ i + 1 }}</span>\n <cqa-custom-input [value]=\"row.get('jsonPath')?.value ?? ''\"\n (valueChange)=\"row.get('jsonPath')?.setValue($event)\" placeholder=\"Json Path\" [fullWidth]=\"true\"\n size=\"sm\" class=\"cqa-api-edit-step-verification-input\" ariaLabel=\"JSON Path\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"row\" [config]=\"verificationSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-dynamic-select [form]=\"row\" [config]=\"verificationDataTypeSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-w-full\"\n (selectionChange)=\"onVerificationDataTypeChange(row, $event)\">\n </cqa-dynamic-select>\n <!-- Expected Value: text for String/Array/Object, number for Number, dropdown for Boolean -->\n <ng-container [ngSwitch]=\"row.get('dataType')?.value\">\n <cqa-dynamic-select *ngSwitchCase=\"'boolean'\" [form]=\"row\"\n [config]=\"verificationExpectedValueBooleanSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-api-edit-step-verification-expected-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input *ngSwitchCase=\"'number'\" [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\" placeholder=\"Expected Value (number)\"\n type=\"number\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-verification-input cqa-api-edit-step-verification-expected-number\"\n ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n <cqa-custom-input *ngSwitchDefault [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\"\n placeholder=\"Expected Value in String\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-verification-input\" ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n </ng-container>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-verification-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeVerificationRow(i)\">\n <svg class=\"cqa-api-edit-step-verification-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n </div>\n </div>\n\n <!-- Status tab content: S.no, Verification dropdown, Expected Value, add/remove rows -->\n <div *ngIf=\"activeResponseVerificationTab === 'status'\" class=\"cqa-api-edit-step-step3-content\">\n <div class=\"cqa-api-edit-step-verification-header-row\">\n <span></span>\n <cqa-button type=\"button\" variant=\"text\" text=\"Add Verification\"\n customClass=\"cqa-api-edit-step-verification-add-link\" (clicked)=\"addStatusVerificationRow()\">\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-status-verification\">\n <div class=\"cqa-api-edit-step-status-verification-header\">\n <span class=\"cqa-api-edit-step-verification-label\">S.no</span>\n <span class=\"cqa-api-edit-step-verification-label\">Verification</span>\n <span class=\"cqa-api-edit-step-verification-label\">Expected Value</span>\n <span class=\"cqa-api-edit-step-verification-label cqa-api-edit-step-verification-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of statusVerificationRows; let i = index; trackBy: trackByStatusVerification\"\n [formGroup]=\"row\" class=\"cqa-api-edit-step-status-verification-row\">\n <span class=\"cqa-api-edit-step-verification-sno\">{{ i + 1 }}</span>\n <cqa-dynamic-select [form]=\"row\" [config]=\"statusVerificationSelectConfig\"\n class=\"cqa-api-edit-step-status-verification-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\" placeholder=\"Expected Value\"\n type=\"number\" [fullWidth]=\"true\" size=\"sm\" class=\"cqa-api-edit-step-verification-input\"\n ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-verification-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeStatusVerificationRow(i)\">\n <svg class=\"cqa-api-edit-step-verification-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Response Preview -->\n <div class=\"cqa-api-edit-step-response\">\n <h3 class=\"cqa-api-edit-step-response-title\">Response Preview</h3>\n <pre class=\"cqa-api-edit-step-response-content\">{{ responsePreview }}</pre>\n </div>\n\n <!-- Step actions: one row, full width. Step 1: Cancel + Next; Step 2: Back + Next; Step 3: Back + Create -->\n <div class=\"cqa-api-edit-step-actions\">\n <ng-container [ngSwitch]=\"currentStep\">\n <ng-container *ngSwitchCase=\"1\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Cancel\"\n customClass=\"cqa-api-edit-step-actions-btn-cancel\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Next\"\n customClass=\"cqa-api-edit-step-actions-btn-next\" (clicked)=\"onNext()\">\n </cqa-button>\n </ng-container>\n <ng-container *ngSwitchCase=\"2\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Back\"\n customClass=\"cqa-api-edit-step-actions-btn-back\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Next\"\n customClass=\"cqa-api-edit-step-actions-btn-next\" (clicked)=\"onNext()\">\n </cqa-button>\n </ng-container>\n <ng-container *ngSwitchCase=\"3\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Back\"\n customClass=\"cqa-api-edit-step-actions-btn-back\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Create\"\n customClass=\"cqa-api-edit-step-actions-btn-create\" (clicked)=\"onCreate()\">\n </cqa-button>\n </ng-container>\n </ng-container>\n </div>\n</div>" }]
|
|
21293
|
+
args: [{ selector: 'cqa-api-edit-step', host: { class: 'cqa-ui-root' }, changeDetection: ChangeDetectionStrategy.Default, template: "<div class=\"cqa-api-edit-step-container cqa-bg-[#ffffff] cqa-flex cqa-flex-col cqa-w-full cqa-h-full cqa-p-[16px] cqa-gap-[12px] cqa-overflow-y-auto cqa-overflow-x-hidden cqa-box-border\">\n\n <h2 class=\"cqa-api-edit-step-title cqa-font-inter cqa-text-[12px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal cqa-text-[#000000] cqa-m-0\">\n {{ editMode ? 'Update API Test Step' : 'Create API Test Step' }}\n </h2>\n\n <div class=\"cqa-api-edit-step-indicator cqa-flex cqa-items-center cqa-gap-0 cqa-max-[767px]:cqa-flex-wrap cqa-max-[767px]:cqa-gap-2 cqa-max-[767px]:cqa-justify-start\"\n [class.cqa-justify-start]=\"stepLabels.length === 1\"\n [class.cqa-justify-between]=\"stepLabels.length !== 1\">\n <ng-container *ngFor=\"let step of stepLabels; let i = index\">\n <cqa-button type=\"button\" variant=\"text\"\n customClass=\"cqa-api-edit-step-indicator-item cqa-api-edit-step-indicator-item--clickable cqa-flex cqa-items-center cqa-gap-[10px] cqa-cursor-pointer cqa-border-none cqa-p-0 cqa-font-inherit cqa-text-inherit cqa-text-left !cqa-bg-transparent\"\n [attr.aria-label]=\"'Step ' + step.index + ': ' + step.label\" [attr.aria-pressed]=\"step.index === currentStep\"\n (clicked)=\"setStep(step.index)\">\n <span class=\"cqa-api-edit-step-indicator-circle cqa-w-8 cqa-h-8 cqa-rounded-full cqa-inline-flex cqa-items-center cqa-justify-center cqa-text-sm cqa-font-medium cqa-leading-none cqa-border-none cqa-shrink-0\"\n [ngClass]=\"step.index === currentStep ? 'cqa-bg-[#4F46E5] cqa-text-white' : 'cqa-bg-[#E0E0E0] cqa-text-[#666666]'\">\n {{ step.index }}\n </span>\n <span class=\"cqa-api-edit-step-indicator-label cqa-text-sm cqa-leading-[18px] cqa-font-normal cqa-max-[767px]:cqa-text-xs\"\n [ngClass]=\"step.index === currentStep ? 'cqa-text-[#4F46E5]' : 'cqa-text-[#666666]'\">\n {{ step.label }}\n </span>\n <div *ngIf=\"i < stepLabels.length - 1\" class=\"cqa-api-edit-step-indicator-line cqa-w-[96px] cqa-h-[2px] cqa-bg-[#E0E0E0] cqa-my-0 cqa-mx-[6px] cqa-shrink-0 cqa-self-center cqa-max-[767px]:cqa-w-[24px] cqa-max-[767px]:cqa-mx-1\" aria-hidden=\"true\"></div>\n </cqa-button>\n </ng-container>\n </div>\n\n <!-- Step content viewport: only the active step body is shown (*ngIf) -->\n <div class=\"cqa-api-edit-step-viewport cqa-w-full\">\n <!-- Step 1: Environment, request, body, response -->\n <div *ngIf=\"currentStep === 1\" class=\"cqa-api-edit-step-panel cqa-flex cqa-flex-col cqa-gap-6 cqa-box-border cqa-w-full\">\n <!-- Environment row: new line, select aligned right -->\n <div class=\"cqa-api-edit-step-environment-row cqa-flex cqa-justify-end cqa-items-center\">\n <cqa-dynamic-select *ngIf=\"environmentForm\" [form]=\"environmentForm\" [config]=\"environmentSelectConfig\"\n class=\"cqa-api-edit-step-environment-select cqa-shrink-0 cqa-w-auto cqa-min-w-[315px] cqa-max-w-[315px] cqa-max-[767px]:cqa-min-w-0 cqa-max-[767px]:cqa-max-w-full cqa-max-[767px]:cqa-w-full [&_.mat-form-field-wrapper]:cqa-pb-0\" aria-label=\"Environment\"\n (selectionChange)=\"onEnvironmentSelectionChange($event)\">\n </cqa-dynamic-select>\n </div>\n\n <!-- Request row: method, URL, buttons -->\n <div class=\"cqa-api-edit-step-request-row cqa-flex cqa-items-center cqa-gap-3 cqa-flex-wrap cqa-max-[767px]:cqa-flex-col cqa-max-[767px]:cqa-items-stretch cqa-max-[767px]:cqa-gap-2.5\">\n <cqa-dynamic-select *ngIf=\"methodForm\" [form]=\"methodForm\" [config]=\"methodSelectConfig\"\n class=\"cqa-api-edit-step-method-select cqa-shrink-0 cqa-w-auto cqa-min-w-[152px] cqa-max-w-[152px] cqa-max-[767px]:cqa-min-w-0 cqa-max-[767px]:cqa-max-w-full cqa-max-[767px]:cqa-w-full\" aria-label=\"HTTP method\"\n (selectionChange)=\"onMethodSelectionChange($event)\">\n </cqa-dynamic-select>\n <div class=\"cqa-api-edit-step-url-wrap cqa-flex-1 cqa-min-w-[200px] cqa-max-[767px]:cqa-min-w-0 cqa-max-[767px]:cqa-w-full [&_cqa-custom-input_.cqa-relative_input]:cqa-h-[40px] [&_cqa-custom-input_.cqa-relative_input]:cqa-bg-white [&_cqa-custom-input_.cqa-relative_input]:cqa-border [&_cqa-custom-input_.cqa-relative_input]:cqa-border-solid [&_cqa-custom-input_.cqa-relative_input]:cqa-border-[#D1D5DB] [&_cqa-custom-input_.cqa-relative_input]:cqa-rounded-md [&_cqa-custom-input_.cqa-relative_input]:cqa-text-sm [&_cqa-custom-input_.cqa-relative_input]:cqa-text-[#374151]\">\n <cqa-custom-input [(value)]=\"url\" [label]=\"''\" placeholder=\"\" [fullWidth]=\"true\" size=\"md\">\n </cqa-custom-input>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-trigger cqa-contents cqa-max-[767px]:cqa-w-full cqa-max-[767px]:!cqa-flex\" (click)=\"openImportCurlPanel()\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Import API cURL\"\n customClass=\"cqa-api-edit-step-btn-outline !cqa-bg-white !cqa-border !cqa-border-solid !cqa-border-[#6B7280] cqa-text-[#414146] cqa-font-inter cqa-text-[14px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal hover:!cqa-bg-[#F9FAFB] hover:!cqa-text-[#414146] cqa-max-[767px]:cqa-w-full\">\n </cqa-button>\n </div>\n <cqa-button variant=\"filled\" btnSize=\"lg\" text=\"Send Request\" (clicked)=\"onSendRequest()\"\n customClass=\"cqa-api-edit-step-btn-primary cqa-font-inter cqa-text-[14px] cqa-font-semibold cqa-leading-[100%] cqa-tracking-normal !cqa-bg-[#3F43EE] cqa-text-[#FBFCFF] !cqa-border-none cqa-py-2.5 cqa-px-6 cqa-gap-2 cqa-rounded-lg cqa-min-h-[37px] cqa-box-border hover:!cqa-bg-[#1B1FEB] cqa-max-[767px]:cqa-w-full\">\n </cqa-button>\n </div>\n\n\n\n <!-- Body content: header section (default) OR import cURL section -->\n <ng-container *ngIf=\"bodyView === 'import-curl'\">\n <div class=\"cqa-api-edit-step-import-curl-panel cqa-flex cqa-flex-col cqa-bg-white cqa-rounded-lg cqa-border cqa-border-solid cqa-border-[#E5E7EB] cqa-shadow-[0_1px_3px_rgba(0,0,0,0.08)] cqa-overflow-hidden\">\n <div class=\"cqa-api-edit-step-import-curl-header cqa-flex cqa-items-center cqa-justify-between cqa-py-3 cqa-px-5 cqa-border-b cqa-border-solid cqa-border-[#E2E8F0] cqa-bg-[#F9FAFB] cqa-rounded-t-lg cqa-max-[767px]:cqa-px-4\">\n <h3 class=\"cqa-api-edit-step-import-curl-title cqa-m-0 cqa-text-xs cqa-font-bold cqa-leading-[18px] cqa-text-[#374151]\">Import API cURL</h3>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-separator cqa-h-px cqa-bg-[#E2E8F0] cqa-my-0 cqa-mx-5\"></div>\n <div class=\"cqa-api-edit-step-import-curl-body\">\n <cqa-custom-textarea [value]=\"importCurlControl.value\"\n (valueChange)=\"importCurlControl.setValue($event)\"\n placeholder=\"Paste your cURL command here (e.g., curl -X POST https://api.example.com/users)\"\n [fullWidth]=\"true\" [rows]=\"8\" resize=\"vertical\" size=\"md\"\n class=\"cqa-api-edit-step-import-curl-textarea\">\n </cqa-custom-textarea>\n </div>\n <div class=\"cqa-api-edit-step-import-curl-footer\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Cancel\"\n customClass=\"cqa-api-edit-step-import-curl-btn-cancel\" (clicked)=\"onCancelImportCurl()\"></cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Import\"\n customClass=\"cqa-api-edit-step-import-curl-btn-import\" (clicked)=\"onImportCurlConfirm()\"></cqa-button>\n </div>\n </div>\n </ng-container>\n\n <ng-container *ngIf=\"bodyView === 'headers'\">\n <div class=\"cqa-api-edit-step-tabs-wrapper\">\n <div class=\"cqa-api-edit-step-tabs\">\n <cqa-button *ngFor=\"let tab of payloadTabs\" type=\"button\" variant=\"text\" [text]=\"tab.label\"\n [customClass]=\"'cqa-api-edit-step-tab' + (activePayloadTab === tab.value ? ' cqa-api-edit-step-tab--active' : '') + (isMethodWithoutBody && (tab.value === 'body' || tab.value === 'params') ? ' cqa-api-edit-step-tab--disabled' : '')\"\n [disabled]=\"isMethodWithoutBody && (tab.value === 'body' || tab.value === 'params')\"\n (clicked)=\"setPayloadTab(tab.value)\">\n </cqa-button>\n </div>\n\n <!-- Payload content (Authorization) -->\n <div *ngIf=\"activePayloadTab === 'authorization'\" class=\"cqa-api-edit-step-payload\"\n [attr.style]=\"'padding: 20px; min-height: 200px;'\">\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 20px;'\">\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 8px; width: fit-content;'\">\n <span [attr.style]=\"'font-size: 11px; font-weight: 600; letter-spacing: 0.02em; color: #6B7280; text-transform: uppercase; line-height: 1.25;'\">AUTH TYPE</span>\n <cqa-dynamic-select *ngIf=\"authTypeForm\" [form]=\"authTypeForm\" [config]=\"authTypeSelectConfig\"\n class=\"cqa-api-edit-step-auth-type-select\" aria-label=\"Auth type\"\n [attr.style]=\"'min-width: 160px;'\">\n </cqa-dynamic-select>\n </div>\n <!-- No Auth: centered message -->\n <div *ngIf=\"selectedAuthType === 'no-auth'\"\n [attr.style]=\"'flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-width: 0; text-align: center;'\">\n <div aria-hidden=\"true\"\n [attr.style]=\"'width: 48px; height: 48px; border-radius: 10px; background: #F3F4F6; display: flex; align-items: center; justify-content: center; flex-shrink: 0;'\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" style=\"display: block;\">\n <rect x=\"5\" y=\"11\" width=\"14\" height=\"2\" rx=\"1\" fill=\"#9CA3AF\"/>\n </svg>\n </div>\n <span [attr.style]=\"'font-size: 16px; font-weight: 600; color: #374151; line-height: 1.25;'\">No Auth</span>\n <div [attr.style]=\"'display: flex; align-items: center; justify-content: center; gap: 6px; flex-wrap: wrap;'\">\n <span [attr.style]=\"'font-size: 14px; font-weight: 400; color: #9CA3AF; line-height: 1.4;'\">This request does not use any authorization.</span>\n <span role=\"img\" aria-label=\"More information\" title=\"This request does not use any authorization.\"\n [attr.style]=\"'display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; color: #9CA3AF; flex-shrink: 0;'\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" style=\"display: block;\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"#9CA3AF\" stroke-width=\"1.5\" fill=\"none\"/>\n <path d=\"M8 7v4M8 5v.5\" stroke=\"#9CA3AF\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n </div>\n </div>\n <!-- Bearer Token: Token label + textarea -->\n <div *ngIf=\"selectedAuthType === 'bearer'\"\n [attr.style]=\"'flex: 1; display: flex; flex-direction: column; gap: 10px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Token</span>\n <cqa-custom-textarea [(value)]=\"bearerToken\"\n placeholder=\"Enter bearer token\"\n [fullWidth]=\"true\" [rows]=\"6\" resize=\"vertical\" size=\"md\"\n class=\"cqa-api-edit-step-auth-token-textarea\" ariaLabel=\"Bearer token\">\n </cqa-custom-textarea>\n </div>\n <!-- OAuth 2.0: Grant Type, Access Token URL, Client ID, Client Secret, Scope, Client Authentication -->\n <div *ngIf=\"selectedAuthType === 'oauth2' && oauth2Form\"\n class=\"cqa-api-edit-step-oauth2-grid\"\n [attr.style]=\"'display: grid; grid-template-columns: 1fr 1fr; gap: 16px 24px; width: 100%;'\">\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Grant Type</span>\n <cqa-dynamic-select *ngIf=\"oauth2Form\" [form]=\"oauth2Form\" [config]=\"oauth2GrantTypeSelectConfig\"\n class=\"cqa-api-edit-step-auth-oauth-select\" aria-label=\"OAuth grant type\"\n [attr.style]=\"'min-width: 0; width: 100%;'\">\n </cqa-dynamic-select>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">OAuth grant type</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Access Token URL</span>\n <cqa-custom-input [value]=\"oauth2Form.get('accessTokenUrl')?.value\"\n (valueChange)=\"oauth2Form.get('accessTokenUrl')?.setValue($event)\"\n [label]=\"''\" placeholder=\"Enter OAuth token endpoint\" [fullWidth]=\"true\" size=\"md\"\n ariaLabel=\"Access Token URL\">\n </cqa-custom-input>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">OAuth token endpoint</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Client ID</span>\n <cqa-custom-input [value]=\"oauth2Form.get('clientId')?.value\"\n (valueChange)=\"oauth2Form.get('clientId')?.setValue($event)\"\n [label]=\"''\" placeholder=\"Enter OAuth client identifier\" [fullWidth]=\"true\" size=\"md\"\n ariaLabel=\"Client ID\">\n </cqa-custom-input>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">OAuth client identifier</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Client Secret</span>\n <cqa-custom-input [value]=\"oauth2Form.get('clientSecret')?.value\"\n (valueChange)=\"oauth2Form.get('clientSecret')?.setValue($event)\"\n type=\"password\" [label]=\"''\" placeholder=\"Enter OAuth client secret\" [fullWidth]=\"true\" size=\"md\"\n ariaLabel=\"Client Secret\">\n </cqa-custom-input>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">OAuth client secret</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Scope</span>\n <cqa-custom-input [value]=\"oauth2Form.get('scope')?.value\"\n (valueChange)=\"oauth2Form.get('scope')?.setValue($event)\"\n [label]=\"''\" placeholder=\"Enter space-separated scopes\" [fullWidth]=\"true\" size=\"md\"\n ariaLabel=\"Scope\">\n </cqa-custom-input>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">Space-separated scopes</span>\n </div>\n <div [attr.style]=\"'display: flex; flex-direction: column; gap: 6px; min-width: 0;'\">\n <span [attr.style]=\"'font-size: 12px; font-weight: 600; color: #374151; line-height: 1.25;'\">Client Authentication</span>\n <cqa-dynamic-select *ngIf=\"oauth2Form\" [form]=\"oauth2Form\" [config]=\"oauth2ClientAuthSelectConfig\"\n class=\"cqa-api-edit-step-auth-oauth-select\" aria-label=\"Client authentication method\"\n [attr.style]=\"'min-width: 0; width: 100%;'\">\n </cqa-dynamic-select>\n <span [attr.style]=\"'font-size: 11px; font-style: italic; color: #6B7280; line-height: 1.3;'\">Client authentication method</span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Payload content (Headers) -->\n <div *ngIf=\"activePayloadTab === 'headers'\" class=\"cqa-api-edit-step-payload\">\n <div class=\"cqa-api-edit-step-headers-grid\">\n <span class=\"cqa-api-edit-step-headers-label\">Header Name</span>\n <span class=\"cqa-api-edit-step-headers-label\">Header Value</span>\n <span class=\"cqa-api-edit-step-headers-label cqa-api-edit-step-headers-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of headerRows; let i = index; trackBy: trackByHeader\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-header-row\">\n <cqa-dynamic-select [form]=\"row\" [config]=\"headerNameSelectConfig\"\n (addCustomValue)=\"onHeaderNameAddCustomValue($event, row)\"\n class=\"cqa-api-edit-step-header-type-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-header-value-input\" ariaLabel=\"Header value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-header-delete'\"\n [tooltip]=\"'Remove header'\" (clicked)=\"removeHeader(i)\">\n <svg class=\"cqa-api-edit-step-header-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-add-header-wrap\">\n <cqa-button type=\"button\" variant=\"text\" text=\"+ Add Header\"\n [customClass]=\"'cqa-api-edit-step-add-header-link'\" (clicked)=\"addHeader()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Payload content (Params): Key\u2013Value table with add/delete rows -->\n <div *ngIf=\"activePayloadTab === 'params'\" class=\"cqa-api-edit-step-payload\">\n <div class=\"cqa-api-edit-step-key-value-grid cqa-api-edit-step-key-value-header\">\n <span class=\"cqa-api-edit-step-key-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-value-label cqa-api-edit-step-key-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of paramsRows; let i = index; trackBy: trackByParams\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeParamsRow(i)\">\n <svg class=\"cqa-api-edit-step-key-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-value-add-btn\" (clicked)=\"addParamsRow()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Payload content (Body only): type, format, text area, Back/Next -->\n <div *ngIf=\"activePayloadTab === 'body'\"\n class=\"cqa-api-edit-step-payload cqa-api-edit-step-payload-editor\">\n <div class=\"cqa-api-edit-step-payload-type-row\">\n <span class=\"cqa-api-edit-step-payload-type-label\">Type</span>\n <div class=\"cqa-api-edit-step-payload-type-radios\">\n <cqa-segment-control [value]=\"payloadType\" [segments]=\"payloadTypeSegments\"\n (valueChange)=\"onPayloadTypeChange($event)\"\n class=\"cqa-api-edit-step-payload-type-segment\">\n </cqa-segment-control>\n </div>\n <div *ngIf=\"payloadType === 'raw'\" class=\"cqa-api-edit-step-payload-format-wrap\">\n <span class=\"cqa-api-edit-step-payload-format-label\">Format:</span>\n <cqa-dynamic-select *ngIf=\"payloadFormatForm\" [form]=\"payloadFormatForm\"\n [config]=\"payloadFormatSelectConfig\" class=\"cqa-api-edit-step-payload-format-select\"\n aria-label=\"Format\">\n </cqa-dynamic-select>\n </div>\n </div>\n <!-- Raw: text area with line numbers (Postman-style payload body) -->\n <div *ngIf=\"payloadType === 'raw'\" class=\"cqa-api-edit-step-payload-body\" #payloadEditorWithLinesRef>\n <div class=\"cqa-api-edit-step-payload-editor-with-lines\">\n <div class=\"cqa-api-edit-step-payload-line-numbers\" aria-hidden=\"true\">\n <span *ngFor=\"let n of payloadLineNumbers\" class=\"cqa-api-edit-step-payload-line-num\">\n <span *ngIf=\"payloadJsonError && payloadJsonError.line === n\"\n class=\"cqa-api-edit-step-payload-line-error-icon\" [title]=\"payloadJsonErrorTooltip\"\n aria-label=\"Parse error on this line\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"7\" cy=\"7\" r=\"6\" fill=\"#EF4444\"/>\n <path d=\"M4 4l6 6M10 4l-6 6\" stroke=\"white\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </span>\n <span class=\"cqa-api-edit-step-payload-line-num-text\">{{ n }}</span>\n </span>\n </div>\n <div class=\"cqa-api-edit-step-payload-textarea-cell\">\n <div class=\"cqa-api-edit-step-payload-textarea cqa-w-full cqa-flex cqa-flex-col cqa-min-h-0\"\n [ngClass]=\"{'cqa-api-edit-step-payload-textarea--error': payloadJsonError}\">\n <textarea #payloadTextareaRef\n class=\"cqa-api-edit-step-payload-textarea-input cqa-w-full cqa-outline-none cqa-box-border\"\n [ngClass]=\"{'cqa-api-edit-step-payload-textarea-input--error': payloadJsonError}\"\n [value]=\"payloadText\"\n placeholder=\"\"\n [attr.aria-label]=\"'Payload'\"\n [attr.aria-invalid]=\"!!payloadJsonError\"\n (input)=\"onPayloadInput($event)\"\n (keydown)=\"onPayloadKeydown($event)\">\n </textarea>\n </div>\n </div>\n </div>\n <p *ngIf=\"payloadJsonError\" class=\"cqa-api-edit-step-payload-json-error-msg\">\n Invalid JSON format. Please check your syntax.\n </p>\n </div>\n\n <!-- x-www-form-urlencoded: Key\u2013Value rows, add/remove dynamically -->\n <div *ngIf=\"payloadType === 'x-www-form-urlencoded'\" class=\"cqa-api-edit-step-key-value\">\n <div class=\"cqa-api-edit-step-key-value-grid cqa-api-edit-step-key-value-header\">\n <span class=\"cqa-api-edit-step-key-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-value-label cqa-api-edit-step-key-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of keyValueRows; let i = index; trackBy: trackByKeyValue\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeKeyValueRow(i)\">\n <svg class=\"cqa-api-edit-step-key-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-value-add-btn\" (clicked)=\"addKeyValueRow()\">\n </cqa-button>\n </div>\n </div>\n\n <!-- Form Data: Key\u2013Type\u2013Value rows; Type is a dropdown (Text/File), add/remove dynamically -->\n <div *ngIf=\"payloadType === 'form-data'\" class=\"cqa-api-edit-step-key-type-value\">\n <div class=\"cqa-api-edit-step-key-type-value-header\">\n <span class=\"cqa-api-edit-step-key-type-value-label\">Key</span>\n <span class=\"cqa-api-edit-step-key-type-value-label\">Type</span>\n <span class=\"cqa-api-edit-step-key-type-value-label\">Value</span>\n <span class=\"cqa-api-edit-step-key-type-value-label cqa-api-edit-step-key-type-value-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of keyTypeValueRows; let i = index; trackBy: trackByKeyTypeValue\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-key-type-value-row\">\n <cqa-custom-input [value]=\"row.get('key')?.value ?? ''\"\n (valueChange)=\"row.get('key')?.setValue($event)\" placeholder=\"Key\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-type-value-input\" ariaLabel=\"Key\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"row\" [config]=\"keyTypeValueTypeSelectConfig\"\n class=\"cqa-api-edit-step-key-type-value-type-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('value')?.value ?? ''\"\n (valueChange)=\"row.get('value')?.setValue($event)\" placeholder=\"Value\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-key-type-value-input\" ariaLabel=\"Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-key-type-value-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeKeyTypeValueRow(i)\">\n <svg class=\"cqa-api-edit-step-key-type-value-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-key-type-value-add-wrap\">\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"+ Add Row\"\n customClass=\"cqa-api-edit-step-key-type-value-add-btn\" (clicked)=\"addKeyTypeValueRow()\">\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n </ng-container>\n\n </div>\n <!-- Step 2: Variable Name: input, validation, Back / Next -->\n <div *ngIf=\"currentStep === 2\" class=\"cqa-api-edit-step-panel cqa-flex cqa-flex-col cqa-gap-6 cqa-box-border cqa-w-full\">\n <div class=\"cqa-api-edit-step-variable-section\">\n <div class=\"cqa-api-edit-step-variable-input-wrap\">\n <cqa-custom-input [(value)]=\"variableName\" [label]=\"''\" placeholder=\"Variable Name\" [fullWidth]=\"true\"\n size=\"md\" (valueChange)=\"onVariableNameChange()\" aria-label=\"Variable Name\">\n </cqa-custom-input>\n </div>\n <p *ngIf=\"variableNameError\" class=\"cqa-api-edit-step-variable-error\" role=\"alert\">{{ variableNameError }}</p>\n </div>\n </div>\n <!-- Step 3: Response Body / Status tabs -->\n <div *ngIf=\"currentStep === 3\" class=\"cqa-api-edit-step-panel cqa-flex cqa-flex-col cqa-gap-6 cqa-box-border cqa-w-full\">\n <div class=\"cqa-api-edit-step-tabs-wrapper\">\n <div class=\"cqa-api-edit-step-tabs\">\n <cqa-button *ngFor=\"let tab of responseVerificationTabs\" type=\"button\" variant=\"text\" [text]=\"tab.label\"\n [customClass]=\"'cqa-api-edit-step-tab' + (activeResponseVerificationTab === tab.value ? ' cqa-api-edit-step-tab--active' : '')\"\n (clicked)=\"setResponseVerificationTab(tab.value)\">\n </cqa-button>\n </div>\n\n <!-- Response Body tab content: verification grid -->\n <div *ngIf=\"activeResponseVerificationTab === 'response-body'\" class=\"cqa-api-edit-step-step3-content\">\n <div class=\"cqa-api-edit-step-verification-header-row\">\n <span></span>\n <cqa-button type=\"button\" variant=\"text\" text=\"Add Verification\"\n customClass=\"cqa-api-edit-step-verification-add-link\" (clicked)=\"addVerificationRow()\">\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-verification\">\n <div class=\"cqa-api-edit-step-verification-grid cqa-api-edit-step-verification-grid-header\">\n <span class=\"cqa-api-edit-step-verification-label\">S.no</span>\n <span class=\"cqa-api-edit-step-verification-label\">JSON Path</span>\n <span class=\"cqa-api-edit-step-verification-label\">Verification</span>\n <span class=\"cqa-api-edit-step-verification-label\">Data Type</span>\n <span class=\"cqa-api-edit-step-verification-label\">Expected Value</span>\n <span class=\"cqa-api-edit-step-verification-label cqa-api-edit-step-verification-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of verificationRows; let i = index; trackBy: trackByVerification\" [formGroup]=\"row\"\n class=\"cqa-api-edit-step-verification-row\">\n <span class=\"cqa-api-edit-step-verification-sno\">{{ i + 1 }}</span>\n <cqa-custom-input [value]=\"row.get('jsonPath')?.value ?? ''\"\n (valueChange)=\"row.get('jsonPath')?.setValue($event)\" placeholder=\"Json Path\" [fullWidth]=\"true\"\n size=\"sm\" class=\"cqa-api-edit-step-verification-input\" ariaLabel=\"JSON Path\">\n </cqa-custom-input>\n <cqa-dynamic-select [form]=\"row\" [config]=\"verificationSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-dynamic-select [form]=\"row\" [config]=\"verificationDataTypeSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-w-full\"\n (selectionChange)=\"onVerificationDataTypeChange(row, $event)\">\n </cqa-dynamic-select>\n <!-- Expected Value: text for String/Array/Object, number for Number, dropdown for Boolean -->\n <ng-container [ngSwitch]=\"row.get('dataType')?.value\">\n <cqa-dynamic-select *ngSwitchCase=\"'boolean'\" [form]=\"row\"\n [config]=\"verificationExpectedValueBooleanSelectConfig\"\n class=\"cqa-api-edit-step-verification-select cqa-api-edit-step-verification-expected-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input *ngSwitchCase=\"'number'\" [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\" placeholder=\"Expected Value (number)\"\n type=\"number\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-verification-input cqa-api-edit-step-verification-expected-number\"\n ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n <cqa-custom-input *ngSwitchDefault [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\"\n placeholder=\"Expected Value in String\" [fullWidth]=\"true\" size=\"sm\"\n class=\"cqa-api-edit-step-verification-input\" ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n </ng-container>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-verification-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeVerificationRow(i)\">\n <svg class=\"cqa-api-edit-step-verification-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n </div>\n </div>\n\n <!-- Status tab content: S.no, Verification dropdown, Expected Value, add/remove rows -->\n <div *ngIf=\"activeResponseVerificationTab === 'status'\" class=\"cqa-api-edit-step-step3-content\">\n <div class=\"cqa-api-edit-step-verification-header-row\">\n <span></span>\n <cqa-button type=\"button\" variant=\"text\" text=\"Add Verification\"\n customClass=\"cqa-api-edit-step-verification-add-link\" (clicked)=\"addStatusVerificationRow()\">\n </cqa-button>\n </div>\n <div class=\"cqa-api-edit-step-status-verification\">\n <div class=\"cqa-api-edit-step-status-verification-header\">\n <span class=\"cqa-api-edit-step-verification-label\">S.no</span>\n <span class=\"cqa-api-edit-step-verification-label\">Verification</span>\n <span class=\"cqa-api-edit-step-verification-label\">Expected Value</span>\n <span class=\"cqa-api-edit-step-verification-label cqa-api-edit-step-verification-label--empty\"\n aria-hidden=\"true\"></span>\n </div>\n <div *ngFor=\"let row of statusVerificationRows; let i = index; trackBy: trackByStatusVerification\"\n [formGroup]=\"row\" class=\"cqa-api-edit-step-status-verification-row\">\n <span class=\"cqa-api-edit-step-verification-sno\">{{ i + 1 }}</span>\n <cqa-dynamic-select [form]=\"row\" [config]=\"statusVerificationSelectConfig\"\n class=\"cqa-api-edit-step-status-verification-select cqa-w-full\">\n </cqa-dynamic-select>\n <cqa-custom-input [value]=\"row.get('expectedValue')?.value ?? ''\"\n (valueChange)=\"row.get('expectedValue')?.setValue($event)\" placeholder=\"Expected Value\"\n type=\"number\" [fullWidth]=\"true\" size=\"sm\" class=\"cqa-api-edit-step-verification-input\"\n ariaLabel=\"Expected Value\">\n </cqa-custom-input>\n <cqa-button type=\"button\" variant=\"text\" [customClass]=\"'cqa-api-edit-step-verification-delete'\"\n [tooltip]=\"'Remove row'\" (clicked)=\"removeStatusVerificationRow(i)\">\n <svg class=\"cqa-api-edit-step-verification-delete-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 16 16\"\n fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">\n <path\n d=\"M10.6663 6V12.6667H5.33301V6H10.6663ZM9.66634 2H6.33301L5.66634 2.66667H3.33301V4H12.6663V2.66667H10.333L9.66634 2ZM11.9997 4.66667H3.99967V12.6667C3.99967 13.4 4.59967 14 5.33301 14H10.6663C11.3997 14 11.9997 13.4 11.9997 12.6667V4.66667Z\"\n fill=\"#F9BFBF\" />\n </svg>\n </cqa-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Response Preview -->\n <div class=\"cqa-api-edit-step-response\">\n <h3 class=\"cqa-api-edit-step-response-title cqa-text-[14px] cqa-font-bold cqa-leading-[20px] cqa-text-[#111827] cqa-m-0 cqa-mb-[12px] cqa-shrink-0\">Response Preview</h3>\n <pre class=\"cqa-api-edit-step-response-content\">{{ responsePreview }}</pre>\n </div>\n\n <!-- Step actions: one row, full width. Step 1: Cancel + Next; Step 2: Back + Next; Step 3: Back + Create -->\n <div class=\"cqa-api-edit-step-actions\">\n <ng-container [ngSwitch]=\"currentStep\">\n <ng-container *ngSwitchCase=\"1\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Cancel\"\n customClass=\"cqa-api-edit-step-actions-btn-cancel\" (clicked)=\"onCancel()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Next\"\n customClass=\"cqa-api-edit-step-actions-btn-next\" (clicked)=\"onNext()\">\n </cqa-button>\n </ng-container>\n <ng-container *ngSwitchCase=\"2\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Back\"\n customClass=\"cqa-api-edit-step-actions-btn-back\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" text=\"Next\"\n customClass=\"cqa-api-edit-step-actions-btn-next\" (clicked)=\"onNext()\">\n </cqa-button>\n </ng-container>\n <ng-container *ngSwitchCase=\"3\">\n <cqa-button type=\"button\" variant=\"outlined\" btnSize=\"lg\" text=\"Back\"\n customClass=\"cqa-api-edit-step-actions-btn-back\" (clicked)=\"onBack()\">\n </cqa-button>\n <cqa-button type=\"button\" variant=\"filled\" btnSize=\"lg\" [text]=\"editMode ? 'Update' : 'Create'\"\n customClass=\"cqa-api-edit-step-actions-btn-create\" (clicked)=\"onCreate()\">\n </cqa-button>\n </ng-container>\n </ng-container>\n </div>\n</div>" }]
|
|
20712
21294
|
}], ctorParameters: function () { return [{ type: i1$1.FormBuilder }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { initialMethod: [{
|
|
20713
21295
|
type: Input
|
|
20714
21296
|
}], initialEnvironment: [{
|
|
@@ -20723,6 +21305,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
20723
21305
|
type: Input
|
|
20724
21306
|
}], initialResponsePreview: [{
|
|
20725
21307
|
type: Input
|
|
21308
|
+
}], initialVariableName: [{
|
|
21309
|
+
type: Input
|
|
21310
|
+
}], editMode: [{
|
|
21311
|
+
type: Input
|
|
20726
21312
|
}], importCurl: [{
|
|
20727
21313
|
type: Output
|
|
20728
21314
|
}], importCurlCancel: [{
|
|
@@ -20731,6 +21317,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
20731
21317
|
type: Output
|
|
20732
21318
|
}], back: [{
|
|
20733
21319
|
type: Output
|
|
21320
|
+
}], cancel: [{
|
|
21321
|
+
type: Output
|
|
20734
21322
|
}], next: [{
|
|
20735
21323
|
type: Output
|
|
20736
21324
|
}], create: [{
|
|
@@ -20741,6 +21329,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.4.0", ngImpor
|
|
|
20741
21329
|
type: Input
|
|
20742
21330
|
}], environmentOptions: [{
|
|
20743
21331
|
type: Input
|
|
21332
|
+
}], authTypeOptions: [{
|
|
21333
|
+
type: Input
|
|
21334
|
+
}], initialAuthType: [{
|
|
21335
|
+
type: Input
|
|
20744
21336
|
}], formatOptions: [{
|
|
20745
21337
|
type: Input
|
|
20746
21338
|
}], initialFormat: [{
|