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

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
@@ -41,7 +41,6 @@ let react_syntax_highlighter_dist_esm_languages_hljs_json_js = require("react-sy
41
41
  react_syntax_highlighter_dist_esm_languages_hljs_json_js = __toESM(react_syntax_highlighter_dist_esm_languages_hljs_json_js, 1);
42
42
  let react_syntax_highlighter_dist_esm_styles_hljs_index_js = require("react-syntax-highlighter/dist/esm/styles/hljs/index.js");
43
43
  react_syntax_highlighter_dist_esm_styles_hljs_index_js = __toESM(react_syntax_highlighter_dist_esm_styles_hljs_index_js, 1);
44
- let nanoid = require("nanoid");
45
44
  //#region src/store/slices/view.ts
46
45
  const createViewSlice = (set) => ({ view: {
47
46
  selectedNodeKey: null,
@@ -2698,6 +2697,7 @@ const PARAM_IN_OPTIONS = [
2698
2697
  value: "path"
2699
2698
  }
2700
2699
  ];
2700
+ const RESPONSE_PARAM_IN_OPTIONS = PARAM_IN_OPTIONS.filter((o) => o.value === "header");
2701
2701
  const PARAM_TYPE_OPTIONS = [
2702
2702
  {
2703
2703
  label: "string",
@@ -2724,7 +2724,7 @@ const PARAM_TYPE_OPTIONS = [
2724
2724
  value: "object"
2725
2725
  }
2726
2726
  ];
2727
- const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initialValues }) => {
2727
+ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initialValues, source }) => {
2728
2728
  const [form] = antd.Form.useForm();
2729
2729
  const [messageApi, contextHolder] = antd.message.useMessage();
2730
2730
  const [confirmModalOpen, setConfirmModalOpen] = (0, react$1.useState)(false);
@@ -2942,6 +2942,7 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
2942
2942
  }
2943
2943
  }));
2944
2944
  const isAddEnabled = mode === "edit" ? hasChanges : !!(nameValue?.trim() && inValue && typeValue);
2945
+ const paramInOptions = source === "response" ? RESPONSE_PARAM_IN_OPTIONS : PARAM_IN_OPTIONS;
2945
2946
  const resetForm = () => {
2946
2947
  form.resetFields();
2947
2948
  setEnumInput("");
@@ -3046,10 +3047,11 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3046
3047
  className: cx("form-body"),
3047
3048
  initialValues: {
3048
3049
  required: true,
3049
- in: "query",
3050
+ in: source === "response" ? "header" : "query",
3050
3051
  type: "string"
3051
3052
  },
3052
- onValuesChange: () => {
3053
+ onValuesChange: (_changed, allValues) => {
3054
+ if (allValues.in === "path") form.setFieldValue("required", true);
3053
3055
  if (mode === "edit" && initialValues) {
3054
3056
  const current = form.getFieldsValue();
3055
3057
  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 +3096,7 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3094
3096
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Select, {
3095
3097
  size: "large",
3096
3098
  placeholder: "Select",
3097
- options: PARAM_IN_OPTIONS
3099
+ options: paramInOptions
3098
3100
  })
3099
3101
  }),
3100
3102
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Form.Item, {
@@ -3121,12 +3123,20 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3121
3123
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3122
3124
  className: cx("switch-row"),
3123
3125
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Switch, {
3124
- checked: requiredValue ?? true,
3126
+ checked: inValue === "path" ? true : requiredValue ?? true,
3127
+ disabled: inValue === "path",
3125
3128
  onChange: (checked) => form.setFieldValue("required", checked),
3126
- style: { backgroundColor: requiredValue ?? true ? token.colorPrimary : void 0 }
3127
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3129
+ style: { backgroundColor: (inValue === "path" ? true : requiredValue ?? true) ? token.colorPrimary : void 0 }
3130
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3128
3131
  className: cx("switch-label"),
3129
- children: "Required?"
3132
+ children: ["Required?", inValue === "path" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3133
+ style: {
3134
+ color: token.colorTextTertiary,
3135
+ fontSize: 12,
3136
+ marginLeft: 4
3137
+ },
3138
+ children: "(Always required for path parameter)"
3139
+ })]
3130
3140
  })]
3131
3141
  })
3132
3142
  }),
@@ -3299,7 +3309,7 @@ const buildViewParamRows = (params) => params.map((p, idx) => ({
3299
3309
  description: p.description ?? "",
3300
3310
  enum: p.enum ?? []
3301
3311
  }));
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 }) => {
3312
+ 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
3313
  const [expandedId, setExpandedId] = (0, react$1.useState)(null);
3304
3314
  const [activeTab, setActiveTab] = (0, react$1.useState)("general");
3305
3315
  (0, react$1.useEffect)(() => {
@@ -3340,6 +3350,48 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3340
3350
  const [showResponseSearch, setShowResponseSearch] = (0, react$1.useState)({});
3341
3351
  const debouncedRequestSearches = useDebounce(requestSearches);
3342
3352
  const debouncedResponseSearches = useDebounce(responseSearches);
3353
+ const [editableRequestContent, setEditableRequestContent] = (0, react$1.useState)({});
3354
+ const [editableResponseContent, setEditableResponseContent] = (0, react$1.useState)({});
3355
+ (0, react$1.useEffect)(() => {
3356
+ if (!openRequestPanels.size) return;
3357
+ openRequestPanels.forEach((epId) => {
3358
+ if (editableRequestContent[epId] !== void 0) return;
3359
+ const val = requestBodySchemas?.[epId];
3360
+ const json = val ? JSON.stringify(val, null, 2) : "";
3361
+ setEditableRequestContent((prev) => ({
3362
+ ...prev,
3363
+ [epId]: json
3364
+ }));
3365
+ });
3366
+ }, [openRequestPanels, requestBodySchemas]);
3367
+ (0, react$1.useEffect)(() => {
3368
+ if (!openResponsePanels.size) return;
3369
+ openResponsePanels.forEach((epId) => {
3370
+ if (editableResponseContent[epId] !== void 0) return;
3371
+ const val = responseBodySchemas?.[epId];
3372
+ const json = val ? JSON.stringify(val, null, 2) : "";
3373
+ setEditableResponseContent((prev) => ({
3374
+ ...prev,
3375
+ [epId]: json
3376
+ }));
3377
+ });
3378
+ }, [openResponsePanels, responseBodySchemas]);
3379
+ const handleValidate = (content) => {
3380
+ try {
3381
+ JSON.parse(content);
3382
+ antd.message.success("Definition is valid JSON.");
3383
+ } catch {
3384
+ antd.message.error("Invalid JSON definition.");
3385
+ }
3386
+ };
3387
+ const handleBeautify = (content, setter) => {
3388
+ try {
3389
+ const parsed = JSON.parse(content);
3390
+ setter(JSON.stringify(parsed, null, 2));
3391
+ } catch {
3392
+ antd.message.error("Could not beautify — content is not valid JSON.");
3393
+ }
3394
+ };
3343
3395
  const { selectNodeByKey } = useNodeSelection();
3344
3396
  const { token: antdToken } = antd.theme.useToken();
3345
3397
  const isMobile = !useBreakpoint$2().md;
@@ -3494,6 +3546,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3494
3546
  userSelect: "none",
3495
3547
  "&:hover": { background: token.colorFillTertiary }
3496
3548
  },
3549
+ [scope("param-row--open")]: { borderRadius: `${token.borderRadius}px ${token.borderRadius}px 0 0` },
3497
3550
  [scope("param-row-icon")]: {
3498
3551
  fontSize: 12,
3499
3552
  transition: "transform 0.2s"
@@ -3501,10 +3554,13 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3501
3554
  [scope("param-row-icon--open")]: { transform: "rotate(180deg)" },
3502
3555
  [scope("code-panel")]: {
3503
3556
  width: "100%",
3504
- overflow: "hidden"
3557
+ overflow: "hidden",
3558
+ background: "#1D2856",
3559
+ borderBottomLeftRadius: 8,
3560
+ borderBottomRightRadius: 8
3505
3561
  },
3506
3562
  [scope("code-area")]: {
3507
- background: token.colorBgSpotlight,
3563
+ background: "#1D2856",
3508
3564
  padding: "10px 12px",
3509
3565
  fontFamily: "Cairo, sans-serif",
3510
3566
  fontSize: 14,
@@ -3516,7 +3572,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3516
3572
  display: "block"
3517
3573
  },
3518
3574
  [scope("code-footer")]: {
3519
- background: token.colorBgSpotlight,
3575
+ background: "#161D40",
3520
3576
  padding: 12,
3521
3577
  borderBottomLeftRadius: 8,
3522
3578
  borderBottomRightRadius: 8,
@@ -4500,8 +4556,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4500
4556
  className: cx("pagination")
4501
4557
  })] });
4502
4558
  })(),
4503
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4504
- className: cx("param-row"),
4559
+ !["GET", "DELETE"].includes(ep.method) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4560
+ className: cx("param-row", openRequestPanels.has(ep.id) ? "param-row--open" : ""),
4505
4561
  style: { marginTop: token.margin },
4506
4562
  onClick: () => toggleRequestPanel(ep.id),
4507
4563
  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 +4568,43 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4512
4568
  })]
4513
4569
  })]
4514
4570
  }),
4515
- openRequestPanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4571
+ !["GET", "DELETE"].includes(ep.method) && openRequestPanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4516
4572
  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)
4573
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
4574
+ value: editableRequestContent[ep.id] ?? "",
4575
+ onChange: (e) => {
4576
+ setEditableRequestContent((prev) => ({
4577
+ ...prev,
4578
+ [ep.id]: e.target.value
4579
+ }));
4580
+ onRequestContentChange?.(ep.id, e.target.value);
4581
+ },
4582
+ rows: Math.max(3, (editableRequestContent[ep.id] ?? "").split("\n").length),
4583
+ style: {
4584
+ fontFamily: "monospace",
4585
+ fontSize: "0.75rem",
4586
+ background: "#1D2856",
4587
+ color: "#fff",
4588
+ outline: "none",
4589
+ boxShadow: "none",
4590
+ border: "none"
4591
+ }
4527
4592
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4528
4593
  className: cx("code-footer"),
4529
4594
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
4530
4595
  ghost: true,
4531
4596
  size: "small",
4532
4597
  className: cx("code-btn"),
4598
+ onClick: () => handleValidate(editableRequestContent[ep.id] ?? ""),
4533
4599
  children: "Validate"
4534
4600
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
4535
4601
  ghost: true,
4536
4602
  size: "small",
4537
4603
  className: cx("code-btn"),
4604
+ onClick: () => handleBeautify(editableRequestContent[ep.id] ?? "", (v) => setEditableRequestContent((prev) => ({
4605
+ ...prev,
4606
+ [ep.id]: v
4607
+ }))),
4538
4608
  children: "Beautify"
4539
4609
  })]
4540
4610
  })]
@@ -4960,7 +5030,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4960
5030
  })] });
4961
5031
  })(),
4962
5032
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4963
- className: cx("param-row"),
5033
+ className: cx("param-row", openResponsePanels.has(ep.id) ? "param-row--open" : ""),
4964
5034
  style: { marginTop: token.margin },
4965
5035
  onClick: () => toggleResponsePanel(ep.id),
4966
5036
  children: [
@@ -4980,27 +5050,41 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4980
5050
  }),
4981
5051
  openResponsePanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4982
5052
  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)
5053
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
5054
+ value: editableResponseContent[ep.id] ?? "",
5055
+ onChange: (e) => {
5056
+ setEditableResponseContent((prev) => ({
5057
+ ...prev,
5058
+ [ep.id]: e.target.value
5059
+ }));
5060
+ onResponseContentChange?.(ep.id, e.target.value);
5061
+ },
5062
+ rows: Math.max(3, (editableResponseContent[ep.id] ?? "").split("\n").length),
5063
+ style: {
5064
+ fontFamily: "monospace",
5065
+ fontSize: "0.75rem",
5066
+ background: "#1D2856",
5067
+ color: "#fff",
5068
+ outline: "none",
5069
+ boxShadow: "none",
5070
+ border: "none"
5071
+ }
4993
5072
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4994
5073
  className: cx("code-footer"),
4995
5074
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
4996
5075
  ghost: true,
4997
5076
  size: "small",
4998
5077
  className: cx("code-btn"),
5078
+ onClick: () => handleValidate(editableResponseContent[ep.id] ?? ""),
4999
5079
  children: "Validate"
5000
5080
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
5001
5081
  ghost: true,
5002
5082
  size: "small",
5003
5083
  className: cx("code-btn"),
5084
+ onClick: () => handleBeautify(editableResponseContent[ep.id] ?? "", (v) => setEditableResponseContent((prev) => ({
5085
+ ...prev,
5086
+ [ep.id]: v
5087
+ }))),
5004
5088
  children: "Beautify"
5005
5089
  })]
5006
5090
  })]
@@ -5147,7 +5231,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5147
5231
  setParamDrawerEndpointId(null);
5148
5232
  setParamDrawerMode("add");
5149
5233
  setEditParamIdx(null);
5150
- }
5234
+ },
5235
+ source: drawerSource
5151
5236
  })
5152
5237
  ]
5153
5238
  }));
@@ -5736,8 +5821,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5736
5821
  className: cx("pagination")
5737
5822
  })] });
5738
5823
  })(),
5739
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5740
- className: cx("param-row"),
5824
+ !["GET", "DELETE"].includes(ep.method) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5825
+ className: cx("param-row", openRequestPanels.has(ep.id) ? "param-row--open" : ""),
5741
5826
  style: { marginTop: token.margin },
5742
5827
  onClick: () => toggleRequestPanel(ep.id),
5743
5828
  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 +5833,43 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5748
5833
  })]
5749
5834
  })]
5750
5835
  }),
5751
- openRequestPanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5836
+ !["GET", "DELETE"].includes(ep.method) && openRequestPanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5752
5837
  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)
5838
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
5839
+ value: editableRequestContent[ep.id] ?? "",
5840
+ onChange: (e) => {
5841
+ setEditableRequestContent((prev) => ({
5842
+ ...prev,
5843
+ [ep.id]: e.target.value
5844
+ }));
5845
+ onRequestContentChange?.(ep.id, e.target.value);
5846
+ },
5847
+ rows: Math.max(3, (editableRequestContent[ep.id] ?? "").split("\n").length),
5848
+ style: {
5849
+ fontFamily: "monospace",
5850
+ fontSize: "0.75rem",
5851
+ background: "#1D2856",
5852
+ color: "#fff",
5853
+ outline: "none",
5854
+ boxShadow: "none",
5855
+ border: "none"
5856
+ }
5763
5857
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5764
5858
  className: cx("code-footer"),
5765
5859
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
5766
5860
  ghost: true,
5767
5861
  size: "small",
5768
5862
  className: cx("code-btn"),
5863
+ onClick: () => handleValidate(editableRequestContent[ep.id] ?? ""),
5769
5864
  children: "Validate"
5770
5865
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
5771
5866
  ghost: true,
5772
5867
  size: "small",
5773
5868
  className: cx("code-btn"),
5869
+ onClick: () => handleBeautify(editableRequestContent[ep.id] ?? "", (v) => setEditableRequestContent((prev) => ({
5870
+ ...prev,
5871
+ [ep.id]: v
5872
+ }))),
5774
5873
  children: "Beautify"
5775
5874
  })]
5776
5875
  })]
@@ -6194,7 +6293,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6194
6293
  })] });
6195
6294
  })(),
6196
6295
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6197
- className: cx("param-row"),
6296
+ className: cx("param-row", openResponsePanels.has(ep.id) ? "param-row--open" : ""),
6198
6297
  style: { marginTop: token.margin },
6199
6298
  onClick: () => toggleResponsePanel(ep.id),
6200
6299
  children: [
@@ -6214,27 +6313,41 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6214
6313
  }),
6215
6314
  openResponsePanels.has(ep.id) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6216
6315
  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)
6316
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
6317
+ value: editableResponseContent[ep.id] ?? "",
6318
+ onChange: (e) => {
6319
+ setEditableResponseContent((prev) => ({
6320
+ ...prev,
6321
+ [ep.id]: e.target.value
6322
+ }));
6323
+ onResponseContentChange?.(ep.id, e.target.value);
6324
+ },
6325
+ rows: Math.max(3, (editableResponseContent[ep.id] ?? "").split("\n").length),
6326
+ style: {
6327
+ fontFamily: "monospace",
6328
+ fontSize: "0.75rem",
6329
+ background: "#1D2856",
6330
+ color: "#fff",
6331
+ outline: "none",
6332
+ boxShadow: "none",
6333
+ border: "none"
6334
+ }
6227
6335
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6228
6336
  className: cx("code-footer"),
6229
6337
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
6230
6338
  ghost: true,
6231
6339
  size: "small",
6232
6340
  className: cx("code-btn"),
6341
+ onClick: () => handleValidate(editableResponseContent[ep.id] ?? ""),
6233
6342
  children: "Validate"
6234
6343
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Button, {
6235
6344
  ghost: true,
6236
6345
  size: "small",
6237
6346
  className: cx("code-btn"),
6347
+ onClick: () => handleBeautify(editableResponseContent[ep.id] ?? "", (v) => setEditableResponseContent((prev) => ({
6348
+ ...prev,
6349
+ [ep.id]: v
6350
+ }))),
6238
6351
  children: "Beautify"
6239
6352
  })]
6240
6353
  })]
@@ -6383,7 +6496,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6383
6496
  setParamDrawerEndpointId(null);
6384
6497
  setParamDrawerMode("add");
6385
6498
  setEditParamIdx(null);
6386
- }
6499
+ },
6500
+ source: drawerSource
6387
6501
  })
6388
6502
  ]
6389
6503
  }));
@@ -6885,9 +6999,9 @@ const TagsSection = ({ tags, collapsed, onToggleCollapse, onAddTag, onEditTag, o
6885
6999
  };
6886
7000
  //#endregion
6887
7001
  //#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_-]+$/;
7002
+ const TAG_NAME_REGEX = /^[A-Za-z0-9_\s-]+$/;
7003
+ const TAG_DESC_REGEX = /^[A-Za-z0-9_\s-]+$/;
7004
+ const EXTERNAL_DOCS_DESC_REGEX = /^[A-Za-z0-9_\s-]+$/;
6891
7005
  const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag }) => {
6892
7006
  const [form] = antd.Form.useForm();
6893
7007
  const [messageApi, contextHolder] = antd.message.useMessage();
@@ -7128,7 +7242,7 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7128
7242
  },
7129
7243
  {
7130
7244
  pattern: TAG_NAME_REGEX,
7131
- message: "Only letters, numbers, underscores, and hyphens"
7245
+ message: "Only letters, numbers, spaces, underscores, and hyphens"
7132
7246
  }
7133
7247
  ],
7134
7248
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input, {
@@ -7149,10 +7263,10 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7149
7263
  rules: [{
7150
7264
  max: 50,
7151
7265
  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
- } }],
7266
+ }, {
7267
+ pattern: TAG_DESC_REGEX,
7268
+ message: "Only letters, numbers, spaces, _ and - allowed"
7269
+ }],
7156
7270
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input.TextArea, {
7157
7271
  showCount: true,
7158
7272
  maxLength: 50,
@@ -7172,10 +7286,10 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7172
7286
  rules: [{
7173
7287
  max: 25,
7174
7288
  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
- } }],
7289
+ }, {
7290
+ pattern: EXTERNAL_DOCS_DESC_REGEX,
7291
+ message: "Only letters, numbers, spaces, _ and - allowed"
7292
+ }],
7179
7293
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(antd.Input, {
7180
7294
  showCount: true,
7181
7295
  maxLength: 25,
@@ -7197,8 +7311,8 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7197
7311
  children: "External Docs Link"
7198
7312
  }),
7199
7313
  rules: [{
7200
- max: 512,
7201
- message: "Maximum 512 characters"
7314
+ max: 500,
7315
+ message: "Maximum 500 characters"
7202
7316
  }, { validator: async () => {
7203
7317
  const desc = form.getFieldValue("externalDocsDescription");
7204
7318
  const link = form.getFieldValue("externalDocsLink");
@@ -8534,7 +8648,7 @@ const Codebox$1 = ({ code, language, wrapLongLines }) => {
8534
8648
  //#endregion
8535
8649
  //#region src/view/console/CodeboxSidebar.tsx
8536
8650
  function CodeboxSidebar$1() {
8537
- const { selectedEndpoint, selectedApi, activeRequestTab, selectedStatusCode, statusCodeOptions, setSelectedStatusCode } = useStore(({ view }) => view);
8651
+ const { selectedEndpoint, selectedApi, selectedStatusCode, statusCodeOptions, setSelectedStatusCode } = useStore(({ view }) => view);
8538
8652
  const httpStatusOptions = (0, react$1.useMemo)(() => statusCodeOptions.map((code) => ({
8539
8653
  value: code,
8540
8654
  label: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
@@ -8567,7 +8681,7 @@ function CodeboxSidebar$1() {
8567
8681
  const queryParams = params.filter((p) => p.in === "query");
8568
8682
  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
8683
  })();
8570
- const hasActiveTabParams = (selectedEndpoint?.parameters ?? []).some((p) => p.in === activeRequestTab);
8684
+ const hasAnyParams = (selectedEndpoint?.parameters ?? []).some((p) => p.in === "header" || p.in === "path" || p.in === "query");
8571
8685
  const { token: antdToken, theme: themeConfig } = antd.theme.useToken();
8572
8686
  const isDark = themeConfig.id == 1;
8573
8687
  const headerBg = isDark ? antdToken.colorBgElevated : "#1d2856";
@@ -8689,7 +8803,7 @@ function CodeboxSidebar$1() {
8689
8803
  }));
8690
8804
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8691
8805
  className: cx("container"),
8692
- children: [hasActiveTabParams && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8806
+ children: [hasAnyParams && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8693
8807
  className: cx("rightCard", "rightCardRequest"),
8694
8808
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8695
8809
  className: cx("rightCardHeader"),
@@ -8744,6 +8858,15 @@ function CodeboxSidebar$1() {
8744
8858
  }
8745
8859
  //#endregion
8746
8860
  //#region src/view/helper/mutate.ts
8861
+ /**
8862
+ * Simple deterministic string hash (djb2 variant).
8863
+ * Produces a stable, short base-36 hash for the same input.
8864
+ */
8865
+ const stableHash = (input) => {
8866
+ let hash = 5381;
8867
+ for (let i = 0; i < input.length; i++) hash = (hash << 5) + hash + input.charCodeAt(i);
8868
+ return (hash >>> 0).toString(36);
8869
+ };
8747
8870
  const resolveSchema = (schema, components) => {
8748
8871
  if (!schema) return void 0;
8749
8872
  if (!schema.$ref) return schema;
@@ -8806,14 +8929,14 @@ const transformOpenApiToDocs = (api) => {
8806
8929
  if (!groupedPathsByTags[tag]) groupedPathsByTags[tag] = [];
8807
8930
  groupedPathsByTags[tag].push({
8808
8931
  ...entry,
8809
- id: `endpoint-${(0, nanoid.nanoid)(8)}`
8932
+ id: `endpoint-${stableHash(entry.method + "-" + entry.path)}`
8810
8933
  });
8811
8934
  });
8812
8935
  else {
8813
8936
  if (!groupedPathsByTags.default) groupedPathsByTags.default = [];
8814
8937
  groupedPathsByTags.default.push({
8815
8938
  ...entry,
8816
- id: `endpoint-${(0, nanoid.nanoid)(8)}`
8939
+ id: `endpoint-${stableHash(entry.method + "-" + entry.path)}`
8817
8940
  });
8818
8941
  }
8819
8942
  }
@@ -8827,7 +8950,7 @@ const transformOpenApiToDocs = (api) => {
8827
8950
  }, {});
8828
8951
  return {
8829
8952
  ...api.info,
8830
- id: `api-${(0, nanoid.nanoid)(8)}`,
8953
+ id: `api-${contextPath ?? "unknown"}`,
8831
8954
  contextPath,
8832
8955
  tags: sortedGroupedPathsByTags,
8833
8956
  servers: api.servers,
@@ -8856,7 +8979,7 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8856
8979
  const [apiNameTouched, setApiNameTouched] = (0, react$1.useState)(false);
8857
8980
  const [localDescription, setLocalDescription] = (0, react$1.useState)("");
8858
8981
  const [descriptionTouched, setDescriptionTouched] = (0, react$1.useState)(false);
8859
- const hasApiNameError = apiNameTouched && (!localApiName.trim() || !/^[A-Za-z0-9_-]+$/.test(localApiName.trim()));
8982
+ const hasApiNameError = apiNameTouched && (!localApiName.trim() || !/^[A-Za-z0-9_\s-]+$/.test(localApiName.trim()));
8860
8983
  const hasDescriptionError = descriptionTouched && !localDescription.trim();
8861
8984
  const hasGeneralError = hasApiNameError || hasDescriptionError;
8862
8985
  const [saveErrors, setSaveErrors] = (0, react$1.useState)([]);
@@ -8866,6 +8989,8 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8866
8989
  const [endpointTags, setEndpointTags] = (0, react$1.useState)({});
8867
8990
  const [endpointParams, setEndpointParams] = (0, react$1.useState)({});
8868
8991
  const [endpointResponseParams, setEndpointResponseParams] = (0, react$1.useState)({});
8992
+ const [endpointRequestBody, setEndpointRequestBody] = (0, react$1.useState)({});
8993
+ const [endpointResponseBody, setEndpointResponseBody] = (0, react$1.useState)({});
8869
8994
  const [tagDrawerState, setTagDrawerState] = (0, react$1.useState)({
8870
8995
  open: false,
8871
8996
  mode: "add"
@@ -8876,7 +9001,7 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8876
9001
  });
8877
9002
  const [localTags, setLocalTags] = (0, react$1.useState)([]);
8878
9003
  const [messageApi, contextHolder] = antd.message.useMessage();
8879
- const { focusedContent, selectedNodeKey, selectedApi, originalData, builtTreeData, selectedEndpoint, setOriginalData, setTransformedData, setBuiltTreeData, setFocusedContent, setExpandedKeys, setSelectedEndpoint } = useStore(({ view }) => view);
9004
+ const { focusedContent, selectedNodeKey, selectedApi, originalData, transformedData, builtTreeData, selectedEndpoint, setOriginalData, setTransformedData, setBuiltTreeData, setSelectedApi, setFocusedContent, setExpandedKeys, setSelectedEndpoint } = useStore(({ view }) => view);
8880
9005
  const { selectFirstApi, selectPreSelectedApi, clearSelection } = useNodeSelection();
8881
9006
  const hasInitializedRef = (0, react$1.useRef)(false);
8882
9007
  const { useBreakpoint } = antd.Grid;
@@ -9100,10 +9225,50 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9100
9225
  });
9101
9226
  return result;
9102
9227
  }, [originalData, selectedApi]);
9228
+ const initialEndpointRequestBody = (0, react$1.useMemo)(() => {
9229
+ if (!originalData || !selectedApi) return {};
9230
+ const rawFile = originalData.find((f) => Object.keys(f.paths)[0] === selectedApi.contextPath);
9231
+ if (!rawFile) return {};
9232
+ const pathMethodToId = {};
9233
+ Object.values(selectedApi.tags).flat().forEach((ep) => {
9234
+ pathMethodToId[`${ep.path}||${ep.method.toLowerCase()}`] = ep.id;
9235
+ });
9236
+ const result = {};
9237
+ Object.entries(rawFile.paths).forEach(([path, methods]) => {
9238
+ Object.entries(methods).forEach(([method, operation]) => {
9239
+ const schema = operation.requestBody?.content?.["application/json"]?.schema;
9240
+ const epId = pathMethodToId[`${path}||${method}`];
9241
+ if (epId && schema) result[epId] = schema;
9242
+ });
9243
+ });
9244
+ return result;
9245
+ }, [originalData, selectedApi]);
9246
+ const initialEndpointResponseBody = (0, react$1.useMemo)(() => {
9247
+ if (!originalData || !selectedApi) return {};
9248
+ const rawFile = originalData.find((f) => Object.keys(f.paths)[0] === selectedApi.contextPath);
9249
+ if (!rawFile) return {};
9250
+ const pathMethodToId = {};
9251
+ Object.values(selectedApi.tags).flat().forEach((ep) => {
9252
+ pathMethodToId[`${ep.path}||${ep.method.toLowerCase()}`] = ep.id;
9253
+ });
9254
+ const result = {};
9255
+ Object.entries(rawFile.paths).forEach(([path, methods]) => {
9256
+ Object.entries(methods).forEach(([method, operation]) => {
9257
+ const responses = operation.responses;
9258
+ if (!responses) return;
9259
+ const schema = responses["200" in responses ? "200" : Object.keys(responses)[0]]?.content?.["application/json"]?.schema;
9260
+ const epId = pathMethodToId[`${path}||${method}`];
9261
+ if (epId && schema) result[epId] = schema;
9262
+ });
9263
+ });
9264
+ return result;
9265
+ }, [originalData, selectedApi]);
9103
9266
  (0, react$1.useEffect)(() => {
9104
9267
  setLocalTags(tagMetadata);
9105
9268
  setEndpointParams(initialEndpointParams);
9106
9269
  setEndpointResponseParams(initialEndpointResponseParams);
9270
+ setEndpointRequestBody(initialEndpointRequestBody);
9271
+ setEndpointResponseBody(initialEndpointResponseBody);
9107
9272
  }, [selectedApi]);
9108
9273
  const hasChanges = (0, react$1.useMemo)(() => {
9109
9274
  if (!selectedApi) return false;
@@ -9318,11 +9483,45 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9318
9483
  else delete methodObj["x-response-params"];
9319
9484
  }
9320
9485
  });
9486
+ Object.entries(endpointRequestBody).forEach(([id, schema]) => {
9487
+ const loc = idToPathMethod[id];
9488
+ if (!loc) return;
9489
+ const pathEntry = cloned.paths[loc.path];
9490
+ if (!pathEntry) return;
9491
+ const methodObj = pathEntry[loc.method];
9492
+ if (!methodObj) return;
9493
+ const methodObjAny = methodObj;
9494
+ if (!methodObjAny.requestBody) methodObjAny.requestBody = {};
9495
+ const rb = methodObjAny.requestBody;
9496
+ if (!rb.content) rb.content = {};
9497
+ rb.content["application/json"] = { schema };
9498
+ });
9499
+ Object.entries(endpointResponseBody).forEach(([id, schema]) => {
9500
+ const loc = idToPathMethod[id];
9501
+ if (!loc) return;
9502
+ const pathEntry = cloned.paths[loc.path];
9503
+ if (!pathEntry) return;
9504
+ const methodObj = pathEntry[loc.method];
9505
+ if (!methodObj) return;
9506
+ const methodObjAny = methodObj;
9507
+ if (!methodObjAny.responses) return;
9508
+ const responses = methodObjAny.responses;
9509
+ const statusCode = "200" in responses ? "200" : Object.keys(responses)[0];
9510
+ if (!responses[statusCode]) return;
9511
+ if (!responses[statusCode].content) responses[statusCode].content = {};
9512
+ responses[statusCode].content["application/json"] = { schema };
9513
+ });
9321
9514
  try {
9322
9515
  await onSave?.(cloned);
9323
9516
  setBannerVisible(false);
9324
9517
  setSaveErrors([]);
9325
9518
  messageApi.success("Changes have been saved and published successfully.");
9519
+ setOriginalData(originalData.map((f) => Object.keys(f.paths)[0] === selectedApi.contextPath ? cloned : f));
9520
+ const newTransformed = [cloned].map(transformOpenApiToDocs)[0];
9521
+ const newTransformedData = (transformedData ?? []).map((t) => t.contextPath === selectedApi.contextPath ? newTransformed : t);
9522
+ setTransformedData(newTransformedData);
9523
+ setBuiltTreeData(buildTreeDataStructure(newTransformedData) ?? []);
9524
+ setSelectedApi(newTransformed);
9326
9525
  } catch (err) {
9327
9526
  let messages = [];
9328
9527
  if (err && typeof err === "object" && "errors" in err) {
@@ -9657,7 +9856,29 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9657
9856
  [endpointId]: prev[endpointId]?.filter((_, i) => i !== idx) ?? []
9658
9857
  }));
9659
9858
  setBannerVisible(true);
9660
- }
9859
+ },
9860
+ onRequestContentChange: (endpointId, jsonString) => {
9861
+ try {
9862
+ const schema = JSON.parse(jsonString);
9863
+ setEndpointRequestBody((prev) => ({
9864
+ ...prev,
9865
+ [endpointId]: schema
9866
+ }));
9867
+ setBannerVisible(true);
9868
+ } catch {}
9869
+ },
9870
+ onResponseContentChange: (endpointId, jsonString) => {
9871
+ try {
9872
+ const schema = JSON.parse(jsonString);
9873
+ setEndpointResponseBody((prev) => ({
9874
+ ...prev,
9875
+ [endpointId]: schema
9876
+ }));
9877
+ setBannerVisible(true);
9878
+ } catch {}
9879
+ },
9880
+ requestBodySchemas: endpointRequestBody,
9881
+ responseBodySchemas: endpointResponseBody
9661
9882
  }, resetKey)
9662
9883
  })
9663
9884
  ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
@@ -9796,7 +10017,29 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9796
10017
  [endpointId]: prev[endpointId]?.filter((_, i) => i !== idx) ?? []
9797
10018
  }));
9798
10019
  setBannerVisible(true);
9799
- }
10020
+ },
10021
+ onRequestContentChange: (endpointId, jsonString) => {
10022
+ try {
10023
+ const schema = JSON.parse(jsonString);
10024
+ setEndpointRequestBody((prev) => ({
10025
+ ...prev,
10026
+ [endpointId]: schema
10027
+ }));
10028
+ setBannerVisible(true);
10029
+ } catch {}
10030
+ },
10031
+ onResponseContentChange: (endpointId, jsonString) => {
10032
+ try {
10033
+ const schema = JSON.parse(jsonString);
10034
+ setEndpointResponseBody((prev) => ({
10035
+ ...prev,
10036
+ [endpointId]: schema
10037
+ }));
10038
+ setBannerVisible(true);
10039
+ } catch {}
10040
+ },
10041
+ requestBodySchemas: endpointRequestBody,
10042
+ responseBodySchemas: endpointResponseBody
9800
10043
  }, resetKey)
9801
10044
  ] })
9802
10045
  })]