@digi-frontend/dgate-api-documentation 4.0.5 → 4.0.7

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/dist/index.cjs CHANGED
@@ -2698,6 +2698,7 @@ const PARAM_IN_OPTIONS = [
2698
2698
  value: "path"
2699
2699
  }
2700
2700
  ];
2701
+ const RESPONSE_PARAM_IN_OPTIONS = PARAM_IN_OPTIONS.filter((o) => o.value === "header");
2701
2702
  const PARAM_TYPE_OPTIONS = [
2702
2703
  {
2703
2704
  label: "string",
@@ -2724,7 +2725,7 @@ const PARAM_TYPE_OPTIONS = [
2724
2725
  value: "object"
2725
2726
  }
2726
2727
  ];
2727
- const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initialValues }) => {
2728
+ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initialValues, source }) => {
2728
2729
  const [form] = antd.Form.useForm();
2729
2730
  const [messageApi, contextHolder] = antd.message.useMessage();
2730
2731
  const [confirmModalOpen, setConfirmModalOpen] = (0, react$1.useState)(false);
@@ -2942,6 +2943,7 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
2942
2943
  }
2943
2944
  }));
2944
2945
  const isAddEnabled = mode === "edit" ? hasChanges : !!(nameValue?.trim() && inValue && typeValue);
2946
+ const paramInOptions = source === "response" ? RESPONSE_PARAM_IN_OPTIONS : PARAM_IN_OPTIONS;
2945
2947
  const resetForm = () => {
2946
2948
  form.resetFields();
2947
2949
  setEnumInput("");
@@ -3046,10 +3048,11 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3046
3048
  className: cx("form-body"),
3047
3049
  initialValues: {
3048
3050
  required: true,
3049
- in: "query",
3051
+ in: source === "response" ? "header" : "query",
3050
3052
  type: "string"
3051
3053
  },
3052
- onValuesChange: () => {
3054
+ onValuesChange: (_changed, allValues) => {
3055
+ if (allValues.in === "path") form.setFieldValue("required", true);
3053
3056
  if (mode === "edit" && initialValues) {
3054
3057
  const current = form.getFieldsValue();
3055
3058
  setHasChanges(current.name !== initialValues.name || current.in !== initialValues.in || current.type !== initialValues.type || current.required !== initialValues.required || (current.description ?? "") !== (initialValues.description ?? "") || JSON.stringify(enumValues) !== JSON.stringify(initialValues.enum ?? []));
@@ -3094,7 +3097,7 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3094
3097
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Select, {
3095
3098
  size: "large",
3096
3099
  placeholder: "Select",
3097
- options: PARAM_IN_OPTIONS
3100
+ options: paramInOptions
3098
3101
  })
3099
3102
  }),
3100
3103
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Form.Item, {
@@ -3121,12 +3124,20 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3121
3124
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3122
3125
  className: cx("switch-row"),
3123
3126
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Switch, {
3124
- checked: requiredValue ?? true,
3127
+ checked: inValue === "path" ? true : requiredValue ?? true,
3128
+ disabled: inValue === "path",
3125
3129
  onChange: (checked) => form.setFieldValue("required", checked),
3126
- style: { backgroundColor: requiredValue ?? true ? token.colorPrimary : void 0 }
3127
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3130
+ style: { backgroundColor: (inValue === "path" ? true : requiredValue ?? true) ? token.colorPrimary : void 0 }
3131
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3128
3132
  className: cx("switch-label"),
3129
- children: "Required?"
3133
+ children: ["Required?", inValue === "path" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3134
+ style: {
3135
+ color: token.colorTextTertiary,
3136
+ fontSize: 12,
3137
+ marginLeft: 4
3138
+ },
3139
+ children: "(Always required for path parameter)"
3140
+ })]
3130
3141
  })]
3131
3142
  })
3132
3143
  }),
@@ -3299,7 +3310,7 @@ const buildViewParamRows = (params) => params.map((p, idx) => ({
3299
3310
  description: p.description ?? "",
3300
3311
  enum: p.enum ?? []
3301
3312
  }));
3302
- const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse, endpointNames, endpointDescs, endpointTags, availableTags, onEndpointNameChange, onEndpointDescChange, onEndpointTagsChange, endpointParams, onAddParameter, onEditParameter, onDeleteParameter, endpointResponseParams, onAddResponseParameter, onEditResponseParameter, onDeleteResponseParameter, mode = "edit", selectedEndpointKey }) => {
3313
+ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse, endpointNames, endpointDescs, endpointTags, availableTags, onEndpointNameChange, onEndpointDescChange, onEndpointTagsChange, endpointParams, onAddParameter, onEditParameter, onDeleteParameter, endpointResponseParams, onAddResponseParameter, onEditResponseParameter, onDeleteResponseParameter, onRequestContentChange, onResponseContentChange, requestBodySchemas, responseBodySchemas, mode = "edit", selectedEndpointKey }) => {
3303
3314
  const [expandedId, setExpandedId] = (0, react$1.useState)(null);
3304
3315
  const [activeTab, setActiveTab] = (0, react$1.useState)("general");
3305
3316
  (0, react$1.useEffect)(() => {
@@ -3340,6 +3351,48 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3340
3351
  const [showResponseSearch, setShowResponseSearch] = (0, react$1.useState)({});
3341
3352
  const debouncedRequestSearches = useDebounce(requestSearches);
3342
3353
  const debouncedResponseSearches = useDebounce(responseSearches);
3354
+ const [editableRequestContent, setEditableRequestContent] = (0, react$1.useState)({});
3355
+ const [editableResponseContent, setEditableResponseContent] = (0, react$1.useState)({});
3356
+ (0, react$1.useEffect)(() => {
3357
+ if (!openRequestPanels.size) return;
3358
+ openRequestPanels.forEach((epId) => {
3359
+ if (editableRequestContent[epId] !== void 0) return;
3360
+ const val = requestBodySchemas?.[epId];
3361
+ const json = val ? JSON.stringify(val, null, 2) : "";
3362
+ setEditableRequestContent((prev) => ({
3363
+ ...prev,
3364
+ [epId]: json
3365
+ }));
3366
+ });
3367
+ }, [openRequestPanels, requestBodySchemas]);
3368
+ (0, react$1.useEffect)(() => {
3369
+ if (!openResponsePanels.size) return;
3370
+ openResponsePanels.forEach((epId) => {
3371
+ if (editableResponseContent[epId] !== void 0) return;
3372
+ const val = responseBodySchemas?.[epId];
3373
+ const json = val ? JSON.stringify(val, null, 2) : "";
3374
+ setEditableResponseContent((prev) => ({
3375
+ ...prev,
3376
+ [epId]: json
3377
+ }));
3378
+ });
3379
+ }, [openResponsePanels, responseBodySchemas]);
3380
+ const handleValidate = (content) => {
3381
+ try {
3382
+ JSON.parse(content);
3383
+ antd.message.success("Definition is valid JSON.");
3384
+ } catch {
3385
+ antd.message.error("Invalid JSON definition.");
3386
+ }
3387
+ };
3388
+ const handleBeautify = (content, setter) => {
3389
+ try {
3390
+ const parsed = JSON.parse(content);
3391
+ setter(JSON.stringify(parsed, null, 2));
3392
+ } catch {
3393
+ antd.message.error("Could not beautify — content is not valid JSON.");
3394
+ }
3395
+ };
3343
3396
  const { selectNodeByKey } = useNodeSelection();
3344
3397
  const { token: antdToken } = antd.theme.useToken();
3345
3398
  const isMobile = !useBreakpoint$2().md;
@@ -3494,6 +3547,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3494
3547
  userSelect: "none",
3495
3548
  "&:hover": { background: token.colorFillTertiary }
3496
3549
  },
3550
+ [scope("param-row--open")]: { borderRadius: `${token.borderRadius}px ${token.borderRadius}px 0 0` },
3497
3551
  [scope("param-row-icon")]: {
3498
3552
  fontSize: 12,
3499
3553
  transition: "transform 0.2s"
@@ -3501,10 +3555,13 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3501
3555
  [scope("param-row-icon--open")]: { transform: "rotate(180deg)" },
3502
3556
  [scope("code-panel")]: {
3503
3557
  width: "100%",
3504
- overflow: "hidden"
3558
+ overflow: "hidden",
3559
+ background: "#1D2856",
3560
+ borderBottomLeftRadius: 8,
3561
+ borderBottomRightRadius: 8
3505
3562
  },
3506
3563
  [scope("code-area")]: {
3507
- background: token.colorBgSpotlight,
3564
+ background: "#1D2856",
3508
3565
  padding: "10px 12px",
3509
3566
  fontFamily: "Cairo, sans-serif",
3510
3567
  fontSize: 14,
@@ -3516,7 +3573,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3516
3573
  display: "block"
3517
3574
  },
3518
3575
  [scope("code-footer")]: {
3519
- background: token.colorBgSpotlight,
3576
+ background: "#161D40",
3520
3577
  padding: 12,
3521
3578
  borderBottomLeftRadius: 8,
3522
3579
  borderBottomRightRadius: 8,
@@ -4500,8 +4557,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4500
4557
  className: cx("pagination")
4501
4558
  })] });
4502
4559
  })(),
4503
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4504
- className: cx("param-row"),
4560
+ !["GET", "DELETE"].includes(ep.method) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4561
+ className: cx("param-row", openRequestPanels.has(ep.id) ? "param-row--open" : ""),
4505
4562
  style: { marginTop: token.margin },
4506
4563
  onClick: () => toggleRequestPanel(ep.id),
4507
4564
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ant_design_icons.DownOutlined, { className: cx("param-row-icon", openRequestPanels.has(ep.id) ? "param-row-icon--open" : "") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -4512,29 +4569,43 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4512
4569
  })]
4513
4570
  })]
4514
4571
  }),
4515
- openRequestPanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4572
+ !["GET", "DELETE"].includes(ep.method) && openRequestPanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4516
4573
  className: cx("code-panel"),
4517
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
4518
- className: cx("code-area"),
4519
- children: JSON.stringify((endpointParams[ep.id] ?? []).map((p) => ({
4520
- name: p.name,
4521
- in: p.in,
4522
- type: p.type,
4523
- required: p.required,
4524
- ...p.description ? { description: p.description } : {},
4525
- ...p.enum && p.enum.length > 0 ? { enum: p.enum } : {}
4526
- })), null, 2)
4574
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
4575
+ value: editableRequestContent[ep.id] ?? "",
4576
+ onChange: (e) => {
4577
+ setEditableRequestContent((prev) => ({
4578
+ ...prev,
4579
+ [ep.id]: e.target.value
4580
+ }));
4581
+ onRequestContentChange?.(ep.id, e.target.value);
4582
+ },
4583
+ rows: Math.max(3, (editableRequestContent[ep.id] ?? "").split("\n").length),
4584
+ style: {
4585
+ fontFamily: "monospace",
4586
+ fontSize: "0.75rem",
4587
+ background: "#1D2856",
4588
+ color: "#fff",
4589
+ outline: "none",
4590
+ boxShadow: "none",
4591
+ border: "none"
4592
+ }
4527
4593
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4528
4594
  className: cx("code-footer"),
4529
4595
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
4530
4596
  ghost: true,
4531
4597
  size: "small",
4532
4598
  className: cx("code-btn"),
4599
+ onClick: () => handleValidate(editableRequestContent[ep.id] ?? ""),
4533
4600
  children: "Validate"
4534
4601
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
4535
4602
  ghost: true,
4536
4603
  size: "small",
4537
4604
  className: cx("code-btn"),
4605
+ onClick: () => handleBeautify(editableRequestContent[ep.id] ?? "", (v) => setEditableRequestContent((prev) => ({
4606
+ ...prev,
4607
+ [ep.id]: v
4608
+ }))),
4538
4609
  children: "Beautify"
4539
4610
  })]
4540
4611
  })]
@@ -4960,7 +5031,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4960
5031
  })] });
4961
5032
  })(),
4962
5033
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4963
- className: cx("param-row"),
5034
+ className: cx("param-row", openResponsePanels.has(ep.id) ? "param-row--open" : ""),
4964
5035
  style: { marginTop: token.margin },
4965
5036
  onClick: () => toggleResponsePanel(ep.id),
4966
5037
  children: [
@@ -4980,27 +5051,41 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4980
5051
  }),
4981
5052
  openResponsePanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4982
5053
  className: cx("code-panel"),
4983
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
4984
- className: cx("code-area"),
4985
- children: JSON.stringify((endpointResponseParams[ep.id] ?? []).map((p) => ({
4986
- name: p.name,
4987
- in: p.in,
4988
- type: p.type,
4989
- required: p.required,
4990
- ...p.description ? { description: p.description } : {},
4991
- ...p.enum && p.enum.length > 0 ? { enum: p.enum } : {}
4992
- })), null, 2)
5054
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
5055
+ value: editableResponseContent[ep.id] ?? "",
5056
+ onChange: (e) => {
5057
+ setEditableResponseContent((prev) => ({
5058
+ ...prev,
5059
+ [ep.id]: e.target.value
5060
+ }));
5061
+ onResponseContentChange?.(ep.id, e.target.value);
5062
+ },
5063
+ rows: Math.max(3, (editableResponseContent[ep.id] ?? "").split("\n").length),
5064
+ style: {
5065
+ fontFamily: "monospace",
5066
+ fontSize: "0.75rem",
5067
+ background: "#1D2856",
5068
+ color: "#fff",
5069
+ outline: "none",
5070
+ boxShadow: "none",
5071
+ border: "none"
5072
+ }
4993
5073
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4994
5074
  className: cx("code-footer"),
4995
5075
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
4996
5076
  ghost: true,
4997
5077
  size: "small",
4998
5078
  className: cx("code-btn"),
5079
+ onClick: () => handleValidate(editableResponseContent[ep.id] ?? ""),
4999
5080
  children: "Validate"
5000
5081
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
5001
5082
  ghost: true,
5002
5083
  size: "small",
5003
5084
  className: cx("code-btn"),
5085
+ onClick: () => handleBeautify(editableResponseContent[ep.id] ?? "", (v) => setEditableResponseContent((prev) => ({
5086
+ ...prev,
5087
+ [ep.id]: v
5088
+ }))),
5004
5089
  children: "Beautify"
5005
5090
  })]
5006
5091
  })]
@@ -5147,7 +5232,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5147
5232
  setParamDrawerEndpointId(null);
5148
5233
  setParamDrawerMode("add");
5149
5234
  setEditParamIdx(null);
5150
- }
5235
+ },
5236
+ source: drawerSource
5151
5237
  })
5152
5238
  ]
5153
5239
  }));
@@ -5736,8 +5822,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5736
5822
  className: cx("pagination")
5737
5823
  })] });
5738
5824
  })(),
5739
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5740
- className: cx("param-row"),
5825
+ !["GET", "DELETE"].includes(ep.method) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5826
+ className: cx("param-row", openRequestPanels.has(ep.id) ? "param-row--open" : ""),
5741
5827
  style: { marginTop: token.margin },
5742
5828
  onClick: () => toggleRequestPanel(ep.id),
5743
5829
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_ant_design_icons.DownOutlined, { className: cx("param-row-icon", openRequestPanels.has(ep.id) ? "param-row-icon--open" : "") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -5748,29 +5834,43 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5748
5834
  })]
5749
5835
  })]
5750
5836
  }),
5751
- openRequestPanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5837
+ !["GET", "DELETE"].includes(ep.method) && openRequestPanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5752
5838
  className: cx("code-panel"),
5753
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
5754
- className: cx("code-area"),
5755
- children: JSON.stringify((endpointParams[ep.id] ?? []).map((p) => ({
5756
- name: p.name,
5757
- in: p.in,
5758
- type: p.type,
5759
- required: p.required,
5760
- ...p.description ? { description: p.description } : {},
5761
- ...p.enum && p.enum.length > 0 ? { enum: p.enum } : {}
5762
- })), null, 2)
5839
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
5840
+ value: editableRequestContent[ep.id] ?? "",
5841
+ onChange: (e) => {
5842
+ setEditableRequestContent((prev) => ({
5843
+ ...prev,
5844
+ [ep.id]: e.target.value
5845
+ }));
5846
+ onRequestContentChange?.(ep.id, e.target.value);
5847
+ },
5848
+ rows: Math.max(3, (editableRequestContent[ep.id] ?? "").split("\n").length),
5849
+ style: {
5850
+ fontFamily: "monospace",
5851
+ fontSize: "0.75rem",
5852
+ background: "#1D2856",
5853
+ color: "#fff",
5854
+ outline: "none",
5855
+ boxShadow: "none",
5856
+ border: "none"
5857
+ }
5763
5858
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5764
5859
  className: cx("code-footer"),
5765
5860
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
5766
5861
  ghost: true,
5767
5862
  size: "small",
5768
5863
  className: cx("code-btn"),
5864
+ onClick: () => handleValidate(editableRequestContent[ep.id] ?? ""),
5769
5865
  children: "Validate"
5770
5866
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
5771
5867
  ghost: true,
5772
5868
  size: "small",
5773
5869
  className: cx("code-btn"),
5870
+ onClick: () => handleBeautify(editableRequestContent[ep.id] ?? "", (v) => setEditableRequestContent((prev) => ({
5871
+ ...prev,
5872
+ [ep.id]: v
5873
+ }))),
5774
5874
  children: "Beautify"
5775
5875
  })]
5776
5876
  })]
@@ -6194,7 +6294,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6194
6294
  })] });
6195
6295
  })(),
6196
6296
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6197
- className: cx("param-row"),
6297
+ className: cx("param-row", openResponsePanels.has(ep.id) ? "param-row--open" : ""),
6198
6298
  style: { marginTop: token.margin },
6199
6299
  onClick: () => toggleResponsePanel(ep.id),
6200
6300
  children: [
@@ -6214,27 +6314,41 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6214
6314
  }),
6215
6315
  openResponsePanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6216
6316
  className: cx("code-panel"),
6217
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
6218
- className: cx("code-area"),
6219
- children: JSON.stringify((endpointResponseParams[ep.id] ?? []).map((p) => ({
6220
- name: p.name,
6221
- in: p.in,
6222
- type: p.type,
6223
- required: p.required,
6224
- ...p.description ? { description: p.description } : {},
6225
- ...p.enum && p.enum.length > 0 ? { enum: p.enum } : {}
6226
- })), null, 2)
6317
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
6318
+ value: editableResponseContent[ep.id] ?? "",
6319
+ onChange: (e) => {
6320
+ setEditableResponseContent((prev) => ({
6321
+ ...prev,
6322
+ [ep.id]: e.target.value
6323
+ }));
6324
+ onResponseContentChange?.(ep.id, e.target.value);
6325
+ },
6326
+ rows: Math.max(3, (editableResponseContent[ep.id] ?? "").split("\n").length),
6327
+ style: {
6328
+ fontFamily: "monospace",
6329
+ fontSize: "0.75rem",
6330
+ background: "#1D2856",
6331
+ color: "#fff",
6332
+ outline: "none",
6333
+ boxShadow: "none",
6334
+ border: "none"
6335
+ }
6227
6336
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6228
6337
  className: cx("code-footer"),
6229
6338
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
6230
6339
  ghost: true,
6231
6340
  size: "small",
6232
6341
  className: cx("code-btn"),
6342
+ onClick: () => handleValidate(editableResponseContent[ep.id] ?? ""),
6233
6343
  children: "Validate"
6234
6344
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
6235
6345
  ghost: true,
6236
6346
  size: "small",
6237
6347
  className: cx("code-btn"),
6348
+ onClick: () => handleBeautify(editableResponseContent[ep.id] ?? "", (v) => setEditableResponseContent((prev) => ({
6349
+ ...prev,
6350
+ [ep.id]: v
6351
+ }))),
6238
6352
  children: "Beautify"
6239
6353
  })]
6240
6354
  })]
@@ -6383,7 +6497,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6383
6497
  setParamDrawerEndpointId(null);
6384
6498
  setParamDrawerMode("add");
6385
6499
  setEditParamIdx(null);
6386
- }
6500
+ },
6501
+ source: drawerSource
6387
6502
  })
6388
6503
  ]
6389
6504
  }));
@@ -6885,9 +7000,9 @@ const TagsSection = ({ tags, collapsed, onToggleCollapse, onAddTag, onEditTag, o
6885
7000
  };
6886
7001
  //#endregion
6887
7002
  //#region src/view/components/ApiPage/components/AddTagDrawer.tsx
6888
- const TAG_NAME_REGEX = /^[A-Za-z0-9_-]+$/;
6889
- const TAG_DESC_REGEX = /^[A-Za-z0-9_-]+$/;
6890
- const EXT_DESC_REGEX = /^[A-Za-z0-9_-]+$/;
7003
+ const TAG_NAME_REGEX = /^[A-Za-z0-9_\s-]+$/;
7004
+ const TAG_DESC_REGEX = /^[A-Za-z0-9_\s-]+$/;
7005
+ const EXTERNAL_DOCS_DESC_REGEX = /^[A-Za-z0-9_\s-]+$/;
6891
7006
  const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag }) => {
6892
7007
  const [form] = antd.Form.useForm();
6893
7008
  const [messageApi, contextHolder] = antd.message.useMessage();
@@ -7128,7 +7243,7 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7128
7243
  },
7129
7244
  {
7130
7245
  pattern: TAG_NAME_REGEX,
7131
- message: "Only letters, numbers, underscores, and hyphens"
7246
+ message: "Only letters, numbers, spaces, underscores, and hyphens"
7132
7247
  }
7133
7248
  ],
7134
7249
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input, {
@@ -7149,10 +7264,10 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7149
7264
  rules: [{
7150
7265
  max: 50,
7151
7266
  message: "Maximum 50 characters"
7152
- }, { validator: (_, value) => {
7153
- if (!value || TAG_DESC_REGEX.test(value)) return Promise.resolve();
7154
- return Promise.reject(/* @__PURE__ */ new Error("Only letters, numbers, underscores, and hyphens"));
7155
- } }],
7267
+ }, {
7268
+ pattern: TAG_DESC_REGEX,
7269
+ message: "Only letters, numbers, spaces, _ and - allowed"
7270
+ }],
7156
7271
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
7157
7272
  showCount: true,
7158
7273
  maxLength: 50,
@@ -7172,10 +7287,10 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7172
7287
  rules: [{
7173
7288
  max: 25,
7174
7289
  message: "Maximum 25 characters"
7175
- }, { validator: (_, value) => {
7176
- if (!value || EXT_DESC_REGEX.test(value)) return Promise.resolve();
7177
- return Promise.reject(/* @__PURE__ */ new Error("Only letters, numbers, underscores, and hyphens"));
7178
- } }],
7290
+ }, {
7291
+ pattern: EXTERNAL_DOCS_DESC_REGEX,
7292
+ message: "Only letters, numbers, spaces, _ and - allowed"
7293
+ }],
7179
7294
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input, {
7180
7295
  showCount: true,
7181
7296
  maxLength: 25,
@@ -7197,8 +7312,8 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7197
7312
  children: "External Docs Link"
7198
7313
  }),
7199
7314
  rules: [{
7200
- max: 512,
7201
- message: "Maximum 512 characters"
7315
+ max: 500,
7316
+ message: "Maximum 500 characters"
7202
7317
  }, { validator: async () => {
7203
7318
  const desc = form.getFieldValue("externalDocsDescription");
7204
7319
  const link = form.getFieldValue("externalDocsLink");
@@ -8534,7 +8649,7 @@ const Codebox$1 = ({ code, language, wrapLongLines }) => {
8534
8649
  //#endregion
8535
8650
  //#region src/view/console/CodeboxSidebar.tsx
8536
8651
  function CodeboxSidebar$1() {
8537
- const { selectedEndpoint, selectedApi, activeRequestTab, selectedStatusCode, statusCodeOptions, setSelectedStatusCode } = useStore(({ view }) => view);
8652
+ const { selectedEndpoint, selectedApi, selectedStatusCode, statusCodeOptions, setSelectedStatusCode } = useStore(({ view }) => view);
8538
8653
  const httpStatusOptions = (0, react$1.useMemo)(() => statusCodeOptions.map((code) => ({
8539
8654
  value: code,
8540
8655
  label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -8567,7 +8682,7 @@ function CodeboxSidebar$1() {
8567
8682
  const queryParams = params.filter((p) => p.in === "query");
8568
8683
  return [`curl --location '${serverUrl}${resolvedPath}${queryParams.length > 0 ? "?" + queryParams.map((p) => `${p.name}=sample-value`).join("&") : ""}'`, ...params.filter((p) => p.in === "header").map((p) => `--header '${p.name}: sample-value'`)];
8569
8684
  })();
8570
- const hasActiveTabParams = (selectedEndpoint?.parameters ?? []).some((p) => p.in === activeRequestTab);
8685
+ const hasAnyParams = (selectedEndpoint?.parameters ?? []).some((p) => p.in === "header" || p.in === "path" || p.in === "query");
8571
8686
  const { token: antdToken, theme: themeConfig } = antd.theme.useToken();
8572
8687
  const isDark = themeConfig.id == 1;
8573
8688
  const headerBg = isDark ? antdToken.colorBgElevated : "#1d2856";
@@ -8689,7 +8804,7 @@ function CodeboxSidebar$1() {
8689
8804
  }));
8690
8805
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8691
8806
  className: cx("container"),
8692
- children: [hasActiveTabParams && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8807
+ children: [hasAnyParams && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8693
8808
  className: cx("rightCard", "rightCardRequest"),
8694
8809
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8695
8810
  className: cx("rightCardHeader"),
@@ -8856,7 +8971,7 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8856
8971
  const [apiNameTouched, setApiNameTouched] = (0, react$1.useState)(false);
8857
8972
  const [localDescription, setLocalDescription] = (0, react$1.useState)("");
8858
8973
  const [descriptionTouched, setDescriptionTouched] = (0, react$1.useState)(false);
8859
- const hasApiNameError = apiNameTouched && (!localApiName.trim() || !/^[A-Za-z0-9_-]+$/.test(localApiName.trim()));
8974
+ const hasApiNameError = apiNameTouched && (!localApiName.trim() || !/^[A-Za-z0-9_\s-]+$/.test(localApiName.trim()));
8860
8975
  const hasDescriptionError = descriptionTouched && !localDescription.trim();
8861
8976
  const hasGeneralError = hasApiNameError || hasDescriptionError;
8862
8977
  const [saveErrors, setSaveErrors] = (0, react$1.useState)([]);
@@ -8866,6 +8981,8 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8866
8981
  const [endpointTags, setEndpointTags] = (0, react$1.useState)({});
8867
8982
  const [endpointParams, setEndpointParams] = (0, react$1.useState)({});
8868
8983
  const [endpointResponseParams, setEndpointResponseParams] = (0, react$1.useState)({});
8984
+ const [endpointRequestBody, setEndpointRequestBody] = (0, react$1.useState)({});
8985
+ const [endpointResponseBody, setEndpointResponseBody] = (0, react$1.useState)({});
8869
8986
  const [tagDrawerState, setTagDrawerState] = (0, react$1.useState)({
8870
8987
  open: false,
8871
8988
  mode: "add"
@@ -8876,7 +8993,7 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8876
8993
  });
8877
8994
  const [localTags, setLocalTags] = (0, react$1.useState)([]);
8878
8995
  const [messageApi, contextHolder] = antd.message.useMessage();
8879
- const { focusedContent, selectedNodeKey, selectedApi, originalData, builtTreeData, selectedEndpoint, setOriginalData, setTransformedData, setBuiltTreeData, setFocusedContent, setExpandedKeys, setSelectedEndpoint } = useStore(({ view }) => view);
8996
+ const { focusedContent, selectedNodeKey, selectedApi, originalData, transformedData, builtTreeData, selectedEndpoint, setOriginalData, setTransformedData, setBuiltTreeData, setSelectedApi, setFocusedContent, setExpandedKeys, setSelectedEndpoint } = useStore(({ view }) => view);
8880
8997
  const { selectFirstApi, selectPreSelectedApi, clearSelection } = useNodeSelection();
8881
8998
  const hasInitializedRef = (0, react$1.useRef)(false);
8882
8999
  const { useBreakpoint } = antd.Grid;
@@ -9100,10 +9217,50 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9100
9217
  });
9101
9218
  return result;
9102
9219
  }, [originalData, selectedApi]);
9220
+ const initialEndpointRequestBody = (0, react$1.useMemo)(() => {
9221
+ if (!originalData || !selectedApi) return {};
9222
+ const rawFile = originalData.find((f) => Object.keys(f.paths)[0] === selectedApi.contextPath);
9223
+ if (!rawFile) return {};
9224
+ const pathMethodToId = {};
9225
+ Object.values(selectedApi.tags).flat().forEach((ep) => {
9226
+ pathMethodToId[`${ep.path}||${ep.method.toLowerCase()}`] = ep.id;
9227
+ });
9228
+ const result = {};
9229
+ Object.entries(rawFile.paths).forEach(([path, methods]) => {
9230
+ Object.entries(methods).forEach(([method, operation]) => {
9231
+ const schema = operation.requestBody?.content?.["application/json"]?.schema;
9232
+ const epId = pathMethodToId[`${path}||${method}`];
9233
+ if (epId && schema) result[epId] = schema;
9234
+ });
9235
+ });
9236
+ return result;
9237
+ }, [originalData, selectedApi]);
9238
+ const initialEndpointResponseBody = (0, react$1.useMemo)(() => {
9239
+ if (!originalData || !selectedApi) return {};
9240
+ const rawFile = originalData.find((f) => Object.keys(f.paths)[0] === selectedApi.contextPath);
9241
+ if (!rawFile) return {};
9242
+ const pathMethodToId = {};
9243
+ Object.values(selectedApi.tags).flat().forEach((ep) => {
9244
+ pathMethodToId[`${ep.path}||${ep.method.toLowerCase()}`] = ep.id;
9245
+ });
9246
+ const result = {};
9247
+ Object.entries(rawFile.paths).forEach(([path, methods]) => {
9248
+ Object.entries(methods).forEach(([method, operation]) => {
9249
+ const responses = operation.responses;
9250
+ if (!responses) return;
9251
+ const schema = responses["200" in responses ? "200" : Object.keys(responses)[0]]?.content?.["application/json"]?.schema;
9252
+ const epId = pathMethodToId[`${path}||${method}`];
9253
+ if (epId && schema) result[epId] = schema;
9254
+ });
9255
+ });
9256
+ return result;
9257
+ }, [originalData, selectedApi]);
9103
9258
  (0, react$1.useEffect)(() => {
9104
9259
  setLocalTags(tagMetadata);
9105
9260
  setEndpointParams(initialEndpointParams);
9106
9261
  setEndpointResponseParams(initialEndpointResponseParams);
9262
+ setEndpointRequestBody(initialEndpointRequestBody);
9263
+ setEndpointResponseBody(initialEndpointResponseBody);
9107
9264
  }, [selectedApi]);
9108
9265
  const hasChanges = (0, react$1.useMemo)(() => {
9109
9266
  if (!selectedApi) return false;
@@ -9318,11 +9475,45 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9318
9475
  else delete methodObj["x-response-params"];
9319
9476
  }
9320
9477
  });
9478
+ Object.entries(endpointRequestBody).forEach(([id, schema]) => {
9479
+ const loc = idToPathMethod[id];
9480
+ if (!loc) return;
9481
+ const pathEntry = cloned.paths[loc.path];
9482
+ if (!pathEntry) return;
9483
+ const methodObj = pathEntry[loc.method];
9484
+ if (!methodObj) return;
9485
+ const methodObjAny = methodObj;
9486
+ if (!methodObjAny.requestBody) methodObjAny.requestBody = {};
9487
+ const rb = methodObjAny.requestBody;
9488
+ if (!rb.content) rb.content = {};
9489
+ rb.content["application/json"] = { schema };
9490
+ });
9491
+ Object.entries(endpointResponseBody).forEach(([id, schema]) => {
9492
+ const loc = idToPathMethod[id];
9493
+ if (!loc) return;
9494
+ const pathEntry = cloned.paths[loc.path];
9495
+ if (!pathEntry) return;
9496
+ const methodObj = pathEntry[loc.method];
9497
+ if (!methodObj) return;
9498
+ const methodObjAny = methodObj;
9499
+ if (!methodObjAny.responses) return;
9500
+ const responses = methodObjAny.responses;
9501
+ const statusCode = "200" in responses ? "200" : Object.keys(responses)[0];
9502
+ if (!responses[statusCode]) return;
9503
+ if (!responses[statusCode].content) responses[statusCode].content = {};
9504
+ responses[statusCode].content["application/json"] = { schema };
9505
+ });
9321
9506
  try {
9322
9507
  await onSave?.(cloned);
9323
9508
  setBannerVisible(false);
9324
9509
  setSaveErrors([]);
9325
9510
  messageApi.success("Changes have been saved and published successfully.");
9511
+ setOriginalData(originalData.map((f) => Object.keys(f.paths)[0] === selectedApi.contextPath ? cloned : f));
9512
+ const newTransformed = [cloned].map(transformOpenApiToDocs)[0];
9513
+ const newTransformedData = (transformedData ?? []).map((t) => t.contextPath === selectedApi.contextPath ? newTransformed : t);
9514
+ setTransformedData(newTransformedData);
9515
+ setBuiltTreeData(buildTreeDataStructure(newTransformedData) ?? []);
9516
+ setSelectedApi(newTransformed);
9326
9517
  } catch (err) {
9327
9518
  let messages = [];
9328
9519
  if (err && typeof err === "object" && "errors" in err) {
@@ -9657,7 +9848,29 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9657
9848
  [endpointId]: prev[endpointId]?.filter((_, i) => i !== idx) ?? []
9658
9849
  }));
9659
9850
  setBannerVisible(true);
9660
- }
9851
+ },
9852
+ onRequestContentChange: (endpointId, jsonString) => {
9853
+ try {
9854
+ const schema = JSON.parse(jsonString);
9855
+ setEndpointRequestBody((prev) => ({
9856
+ ...prev,
9857
+ [endpointId]: schema
9858
+ }));
9859
+ setBannerVisible(true);
9860
+ } catch {}
9861
+ },
9862
+ onResponseContentChange: (endpointId, jsonString) => {
9863
+ try {
9864
+ const schema = JSON.parse(jsonString);
9865
+ setEndpointResponseBody((prev) => ({
9866
+ ...prev,
9867
+ [endpointId]: schema
9868
+ }));
9869
+ setBannerVisible(true);
9870
+ } catch {}
9871
+ },
9872
+ requestBodySchemas: endpointRequestBody,
9873
+ responseBodySchemas: endpointResponseBody
9661
9874
  }, resetKey)
9662
9875
  })
9663
9876
  ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
@@ -9796,7 +10009,29 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9796
10009
  [endpointId]: prev[endpointId]?.filter((_, i) => i !== idx) ?? []
9797
10010
  }));
9798
10011
  setBannerVisible(true);
9799
- }
10012
+ },
10013
+ onRequestContentChange: (endpointId, jsonString) => {
10014
+ try {
10015
+ const schema = JSON.parse(jsonString);
10016
+ setEndpointRequestBody((prev) => ({
10017
+ ...prev,
10018
+ [endpointId]: schema
10019
+ }));
10020
+ setBannerVisible(true);
10021
+ } catch {}
10022
+ },
10023
+ onResponseContentChange: (endpointId, jsonString) => {
10024
+ try {
10025
+ const schema = JSON.parse(jsonString);
10026
+ setEndpointResponseBody((prev) => ({
10027
+ ...prev,
10028
+ [endpointId]: schema
10029
+ }));
10030
+ setBannerVisible(true);
10031
+ } catch {}
10032
+ },
10033
+ requestBodySchemas: endpointRequestBody,
10034
+ responseBodySchemas: endpointResponseBody
9800
10035
  }, resetKey)
9801
10036
  ] })
9802
10037
  })]