@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.mjs CHANGED
@@ -12,7 +12,6 @@ import Title from "antd/es/typography/Title.js";
12
12
  import { Light } from "react-syntax-highlighter";
13
13
  import json from "react-syntax-highlighter/dist/esm/languages/hljs/json.js";
14
14
  import * as hljs from "react-syntax-highlighter/dist/esm/styles/hljs/index.js";
15
- import { nanoid } from "nanoid";
16
15
  //#region src/store/slices/view.ts
17
16
  const createViewSlice = (set) => ({ view: {
18
17
  selectedNodeKey: null,
@@ -2669,6 +2668,7 @@ const PARAM_IN_OPTIONS = [
2669
2668
  value: "path"
2670
2669
  }
2671
2670
  ];
2671
+ const RESPONSE_PARAM_IN_OPTIONS = PARAM_IN_OPTIONS.filter((o) => o.value === "header");
2672
2672
  const PARAM_TYPE_OPTIONS = [
2673
2673
  {
2674
2674
  label: "string",
@@ -2695,7 +2695,7 @@ const PARAM_TYPE_OPTIONS = [
2695
2695
  value: "object"
2696
2696
  }
2697
2697
  ];
2698
- const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initialValues }) => {
2698
+ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initialValues, source }) => {
2699
2699
  const [form] = Form.useForm();
2700
2700
  const [messageApi, contextHolder] = message.useMessage();
2701
2701
  const [confirmModalOpen, setConfirmModalOpen] = useState(false);
@@ -2913,6 +2913,7 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
2913
2913
  }
2914
2914
  }));
2915
2915
  const isAddEnabled = mode === "edit" ? hasChanges : !!(nameValue?.trim() && inValue && typeValue);
2916
+ const paramInOptions = source === "response" ? RESPONSE_PARAM_IN_OPTIONS : PARAM_IN_OPTIONS;
2916
2917
  const resetForm = () => {
2917
2918
  form.resetFields();
2918
2919
  setEnumInput("");
@@ -3017,10 +3018,11 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3017
3018
  className: cx("form-body"),
3018
3019
  initialValues: {
3019
3020
  required: true,
3020
- in: "query",
3021
+ in: source === "response" ? "header" : "query",
3021
3022
  type: "string"
3022
3023
  },
3023
- onValuesChange: () => {
3024
+ onValuesChange: (_changed, allValues) => {
3025
+ if (allValues.in === "path") form.setFieldValue("required", true);
3024
3026
  if (mode === "edit" && initialValues) {
3025
3027
  const current = form.getFieldsValue();
3026
3028
  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 ?? []));
@@ -3065,7 +3067,7 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3065
3067
  children: /* @__PURE__ */ jsx(Select, {
3066
3068
  size: "large",
3067
3069
  placeholder: "Select",
3068
- options: PARAM_IN_OPTIONS
3070
+ options: paramInOptions
3069
3071
  })
3070
3072
  }),
3071
3073
  /* @__PURE__ */ jsx(Form.Item, {
@@ -3092,12 +3094,20 @@ const AddParameterDrawer = ({ open, onClose, onAdd, onEdit, mode = "add", initia
3092
3094
  children: /* @__PURE__ */ jsxs("div", {
3093
3095
  className: cx("switch-row"),
3094
3096
  children: [/* @__PURE__ */ jsx(Switch, {
3095
- checked: requiredValue ?? true,
3097
+ checked: inValue === "path" ? true : requiredValue ?? true,
3098
+ disabled: inValue === "path",
3096
3099
  onChange: (checked) => form.setFieldValue("required", checked),
3097
- style: { backgroundColor: requiredValue ?? true ? token.colorPrimary : void 0 }
3098
- }), /* @__PURE__ */ jsx("span", {
3100
+ style: { backgroundColor: (inValue === "path" ? true : requiredValue ?? true) ? token.colorPrimary : void 0 }
3101
+ }), /* @__PURE__ */ jsxs("span", {
3099
3102
  className: cx("switch-label"),
3100
- children: "Required?"
3103
+ children: ["Required?", inValue === "path" && /* @__PURE__ */ jsx("span", {
3104
+ style: {
3105
+ color: token.colorTextTertiary,
3106
+ fontSize: 12,
3107
+ marginLeft: 4
3108
+ },
3109
+ children: "(Always required for path parameter)"
3110
+ })]
3101
3111
  })]
3102
3112
  })
3103
3113
  }),
@@ -3270,7 +3280,7 @@ const buildViewParamRows = (params) => params.map((p, idx) => ({
3270
3280
  description: p.description ?? "",
3271
3281
  enum: p.enum ?? []
3272
3282
  }));
3273
- const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse, endpointNames, endpointDescs, endpointTags, availableTags, onEndpointNameChange, onEndpointDescChange, onEndpointTagsChange, endpointParams, onAddParameter, onEditParameter, onDeleteParameter, endpointResponseParams, onAddResponseParameter, onEditResponseParameter, onDeleteResponseParameter, mode = "edit", selectedEndpointKey }) => {
3283
+ 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 }) => {
3274
3284
  const [expandedId, setExpandedId] = useState(null);
3275
3285
  const [activeTab, setActiveTab] = useState("general");
3276
3286
  useEffect(() => {
@@ -3311,6 +3321,48 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3311
3321
  const [showResponseSearch, setShowResponseSearch] = useState({});
3312
3322
  const debouncedRequestSearches = useDebounce(requestSearches);
3313
3323
  const debouncedResponseSearches = useDebounce(responseSearches);
3324
+ const [editableRequestContent, setEditableRequestContent] = useState({});
3325
+ const [editableResponseContent, setEditableResponseContent] = useState({});
3326
+ useEffect(() => {
3327
+ if (!openRequestPanels.size) return;
3328
+ openRequestPanels.forEach((epId) => {
3329
+ if (editableRequestContent[epId] !== void 0) return;
3330
+ const val = requestBodySchemas?.[epId];
3331
+ const json = val ? JSON.stringify(val, null, 2) : "";
3332
+ setEditableRequestContent((prev) => ({
3333
+ ...prev,
3334
+ [epId]: json
3335
+ }));
3336
+ });
3337
+ }, [openRequestPanels, requestBodySchemas]);
3338
+ useEffect(() => {
3339
+ if (!openResponsePanels.size) return;
3340
+ openResponsePanels.forEach((epId) => {
3341
+ if (editableResponseContent[epId] !== void 0) return;
3342
+ const val = responseBodySchemas?.[epId];
3343
+ const json = val ? JSON.stringify(val, null, 2) : "";
3344
+ setEditableResponseContent((prev) => ({
3345
+ ...prev,
3346
+ [epId]: json
3347
+ }));
3348
+ });
3349
+ }, [openResponsePanels, responseBodySchemas]);
3350
+ const handleValidate = (content) => {
3351
+ try {
3352
+ JSON.parse(content);
3353
+ message.success("Definition is valid JSON.");
3354
+ } catch {
3355
+ message.error("Invalid JSON definition.");
3356
+ }
3357
+ };
3358
+ const handleBeautify = (content, setter) => {
3359
+ try {
3360
+ const parsed = JSON.parse(content);
3361
+ setter(JSON.stringify(parsed, null, 2));
3362
+ } catch {
3363
+ message.error("Could not beautify — content is not valid JSON.");
3364
+ }
3365
+ };
3314
3366
  const { selectNodeByKey } = useNodeSelection();
3315
3367
  const { token: antdToken } = theme.useToken();
3316
3368
  const isMobile = !useBreakpoint$2().md;
@@ -3465,6 +3517,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3465
3517
  userSelect: "none",
3466
3518
  "&:hover": { background: token.colorFillTertiary }
3467
3519
  },
3520
+ [scope("param-row--open")]: { borderRadius: `${token.borderRadius}px ${token.borderRadius}px 0 0` },
3468
3521
  [scope("param-row-icon")]: {
3469
3522
  fontSize: 12,
3470
3523
  transition: "transform 0.2s"
@@ -3472,10 +3525,13 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3472
3525
  [scope("param-row-icon--open")]: { transform: "rotate(180deg)" },
3473
3526
  [scope("code-panel")]: {
3474
3527
  width: "100%",
3475
- overflow: "hidden"
3528
+ overflow: "hidden",
3529
+ background: "#1D2856",
3530
+ borderBottomLeftRadius: 8,
3531
+ borderBottomRightRadius: 8
3476
3532
  },
3477
3533
  [scope("code-area")]: {
3478
- background: token.colorBgSpotlight,
3534
+ background: "#1D2856",
3479
3535
  padding: "10px 12px",
3480
3536
  fontFamily: "Cairo, sans-serif",
3481
3537
  fontSize: 14,
@@ -3487,7 +3543,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
3487
3543
  display: "block"
3488
3544
  },
3489
3545
  [scope("code-footer")]: {
3490
- background: token.colorBgSpotlight,
3546
+ background: "#161D40",
3491
3547
  padding: 12,
3492
3548
  borderBottomLeftRadius: 8,
3493
3549
  borderBottomRightRadius: 8,
@@ -4471,8 +4527,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4471
4527
  className: cx("pagination")
4472
4528
  })] });
4473
4529
  })(),
4474
- /* @__PURE__ */ jsxs("div", {
4475
- className: cx("param-row"),
4530
+ !["GET", "DELETE"].includes(ep.method) && /* @__PURE__ */ jsxs("div", {
4531
+ className: cx("param-row", openRequestPanels.has(ep.id) ? "param-row--open" : ""),
4476
4532
  style: { marginTop: token.margin },
4477
4533
  onClick: () => toggleRequestPanel(ep.id),
4478
4534
  children: [/* @__PURE__ */ jsx(DownOutlined, { className: cx("param-row-icon", openRequestPanels.has(ep.id) ? "param-row-icon--open" : "") }), /* @__PURE__ */ jsxs("span", {
@@ -4483,29 +4539,43 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4483
4539
  })]
4484
4540
  })]
4485
4541
  }),
4486
- openRequestPanels.has(ep.id) && /* @__PURE__ */ jsxs("div", {
4542
+ !["GET", "DELETE"].includes(ep.method) && openRequestPanels.has(ep.id) && /* @__PURE__ */ jsxs("div", {
4487
4543
  className: cx("code-panel"),
4488
- children: [/* @__PURE__ */ jsx("code", {
4489
- className: cx("code-area"),
4490
- children: JSON.stringify((endpointParams[ep.id] ?? []).map((p) => ({
4491
- name: p.name,
4492
- in: p.in,
4493
- type: p.type,
4494
- required: p.required,
4495
- ...p.description ? { description: p.description } : {},
4496
- ...p.enum && p.enum.length > 0 ? { enum: p.enum } : {}
4497
- })), null, 2)
4544
+ children: [/* @__PURE__ */ jsx(Input.TextArea, {
4545
+ value: editableRequestContent[ep.id] ?? "",
4546
+ onChange: (e) => {
4547
+ setEditableRequestContent((prev) => ({
4548
+ ...prev,
4549
+ [ep.id]: e.target.value
4550
+ }));
4551
+ onRequestContentChange?.(ep.id, e.target.value);
4552
+ },
4553
+ rows: Math.max(3, (editableRequestContent[ep.id] ?? "").split("\n").length),
4554
+ style: {
4555
+ fontFamily: "monospace",
4556
+ fontSize: "0.75rem",
4557
+ background: "#1D2856",
4558
+ color: "#fff",
4559
+ outline: "none",
4560
+ boxShadow: "none",
4561
+ border: "none"
4562
+ }
4498
4563
  }), /* @__PURE__ */ jsxs("div", {
4499
4564
  className: cx("code-footer"),
4500
4565
  children: [/* @__PURE__ */ jsx(Button, {
4501
4566
  ghost: true,
4502
4567
  size: "small",
4503
4568
  className: cx("code-btn"),
4569
+ onClick: () => handleValidate(editableRequestContent[ep.id] ?? ""),
4504
4570
  children: "Validate"
4505
4571
  }), /* @__PURE__ */ jsx(Button, {
4506
4572
  ghost: true,
4507
4573
  size: "small",
4508
4574
  className: cx("code-btn"),
4575
+ onClick: () => handleBeautify(editableRequestContent[ep.id] ?? "", (v) => setEditableRequestContent((prev) => ({
4576
+ ...prev,
4577
+ [ep.id]: v
4578
+ }))),
4509
4579
  children: "Beautify"
4510
4580
  })]
4511
4581
  })]
@@ -4931,7 +5001,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4931
5001
  })] });
4932
5002
  })(),
4933
5003
  /* @__PURE__ */ jsxs("div", {
4934
- className: cx("param-row"),
5004
+ className: cx("param-row", openResponsePanels.has(ep.id) ? "param-row--open" : ""),
4935
5005
  style: { marginTop: token.margin },
4936
5006
  onClick: () => toggleResponsePanel(ep.id),
4937
5007
  children: [
@@ -4951,27 +5021,41 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
4951
5021
  }),
4952
5022
  openResponsePanels.has(ep.id) && /* @__PURE__ */ jsxs("div", {
4953
5023
  className: cx("code-panel"),
4954
- children: [/* @__PURE__ */ jsx("code", {
4955
- className: cx("code-area"),
4956
- children: JSON.stringify((endpointResponseParams[ep.id] ?? []).map((p) => ({
4957
- name: p.name,
4958
- in: p.in,
4959
- type: p.type,
4960
- required: p.required,
4961
- ...p.description ? { description: p.description } : {},
4962
- ...p.enum && p.enum.length > 0 ? { enum: p.enum } : {}
4963
- })), null, 2)
5024
+ children: [/* @__PURE__ */ jsx(Input.TextArea, {
5025
+ value: editableResponseContent[ep.id] ?? "",
5026
+ onChange: (e) => {
5027
+ setEditableResponseContent((prev) => ({
5028
+ ...prev,
5029
+ [ep.id]: e.target.value
5030
+ }));
5031
+ onResponseContentChange?.(ep.id, e.target.value);
5032
+ },
5033
+ rows: Math.max(3, (editableResponseContent[ep.id] ?? "").split("\n").length),
5034
+ style: {
5035
+ fontFamily: "monospace",
5036
+ fontSize: "0.75rem",
5037
+ background: "#1D2856",
5038
+ color: "#fff",
5039
+ outline: "none",
5040
+ boxShadow: "none",
5041
+ border: "none"
5042
+ }
4964
5043
  }), /* @__PURE__ */ jsxs("div", {
4965
5044
  className: cx("code-footer"),
4966
5045
  children: [/* @__PURE__ */ jsx(Button, {
4967
5046
  ghost: true,
4968
5047
  size: "small",
4969
5048
  className: cx("code-btn"),
5049
+ onClick: () => handleValidate(editableResponseContent[ep.id] ?? ""),
4970
5050
  children: "Validate"
4971
5051
  }), /* @__PURE__ */ jsx(Button, {
4972
5052
  ghost: true,
4973
5053
  size: "small",
4974
5054
  className: cx("code-btn"),
5055
+ onClick: () => handleBeautify(editableResponseContent[ep.id] ?? "", (v) => setEditableResponseContent((prev) => ({
5056
+ ...prev,
5057
+ [ep.id]: v
5058
+ }))),
4975
5059
  children: "Beautify"
4976
5060
  })]
4977
5061
  })]
@@ -5118,7 +5202,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5118
5202
  setParamDrawerEndpointId(null);
5119
5203
  setParamDrawerMode("add");
5120
5204
  setEditParamIdx(null);
5121
- }
5205
+ },
5206
+ source: drawerSource
5122
5207
  })
5123
5208
  ]
5124
5209
  }));
@@ -5707,8 +5792,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5707
5792
  className: cx("pagination")
5708
5793
  })] });
5709
5794
  })(),
5710
- /* @__PURE__ */ jsxs("div", {
5711
- className: cx("param-row"),
5795
+ !["GET", "DELETE"].includes(ep.method) && /* @__PURE__ */ jsxs("div", {
5796
+ className: cx("param-row", openRequestPanels.has(ep.id) ? "param-row--open" : ""),
5712
5797
  style: { marginTop: token.margin },
5713
5798
  onClick: () => toggleRequestPanel(ep.id),
5714
5799
  children: [/* @__PURE__ */ jsx(DownOutlined, { className: cx("param-row-icon", openRequestPanels.has(ep.id) ? "param-row-icon--open" : "") }), /* @__PURE__ */ jsxs("span", {
@@ -5719,29 +5804,43 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
5719
5804
  })]
5720
5805
  })]
5721
5806
  }),
5722
- openRequestPanels.has(ep.id) && /* @__PURE__ */ jsxs("div", {
5807
+ !["GET", "DELETE"].includes(ep.method) && openRequestPanels.has(ep.id) && /* @__PURE__ */ jsxs("div", {
5723
5808
  className: cx("code-panel"),
5724
- children: [/* @__PURE__ */ jsx("code", {
5725
- className: cx("code-area"),
5726
- children: JSON.stringify((endpointParams[ep.id] ?? []).map((p) => ({
5727
- name: p.name,
5728
- in: p.in,
5729
- type: p.type,
5730
- required: p.required,
5731
- ...p.description ? { description: p.description } : {},
5732
- ...p.enum && p.enum.length > 0 ? { enum: p.enum } : {}
5733
- })), null, 2)
5809
+ children: [/* @__PURE__ */ jsx(Input.TextArea, {
5810
+ value: editableRequestContent[ep.id] ?? "",
5811
+ onChange: (e) => {
5812
+ setEditableRequestContent((prev) => ({
5813
+ ...prev,
5814
+ [ep.id]: e.target.value
5815
+ }));
5816
+ onRequestContentChange?.(ep.id, e.target.value);
5817
+ },
5818
+ rows: Math.max(3, (editableRequestContent[ep.id] ?? "").split("\n").length),
5819
+ style: {
5820
+ fontFamily: "monospace",
5821
+ fontSize: "0.75rem",
5822
+ background: "#1D2856",
5823
+ color: "#fff",
5824
+ outline: "none",
5825
+ boxShadow: "none",
5826
+ border: "none"
5827
+ }
5734
5828
  }), /* @__PURE__ */ jsxs("div", {
5735
5829
  className: cx("code-footer"),
5736
5830
  children: [/* @__PURE__ */ jsx(Button, {
5737
5831
  ghost: true,
5738
5832
  size: "small",
5739
5833
  className: cx("code-btn"),
5834
+ onClick: () => handleValidate(editableRequestContent[ep.id] ?? ""),
5740
5835
  children: "Validate"
5741
5836
  }), /* @__PURE__ */ jsx(Button, {
5742
5837
  ghost: true,
5743
5838
  size: "small",
5744
5839
  className: cx("code-btn"),
5840
+ onClick: () => handleBeautify(editableRequestContent[ep.id] ?? "", (v) => setEditableRequestContent((prev) => ({
5841
+ ...prev,
5842
+ [ep.id]: v
5843
+ }))),
5745
5844
  children: "Beautify"
5746
5845
  })]
5747
5846
  })]
@@ -6165,7 +6264,7 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6165
6264
  })] });
6166
6265
  })(),
6167
6266
  /* @__PURE__ */ jsxs("div", {
6168
- className: cx("param-row"),
6267
+ className: cx("param-row", openResponsePanels.has(ep.id) ? "param-row--open" : ""),
6169
6268
  style: { marginTop: token.margin },
6170
6269
  onClick: () => toggleResponsePanel(ep.id),
6171
6270
  children: [
@@ -6185,27 +6284,41 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6185
6284
  }),
6186
6285
  openResponsePanels.has(ep.id) && /* @__PURE__ */ jsxs("div", {
6187
6286
  className: cx("code-panel"),
6188
- children: [/* @__PURE__ */ jsx("code", {
6189
- className: cx("code-area"),
6190
- children: JSON.stringify((endpointResponseParams[ep.id] ?? []).map((p) => ({
6191
- name: p.name,
6192
- in: p.in,
6193
- type: p.type,
6194
- required: p.required,
6195
- ...p.description ? { description: p.description } : {},
6196
- ...p.enum && p.enum.length > 0 ? { enum: p.enum } : {}
6197
- })), null, 2)
6287
+ children: [/* @__PURE__ */ jsx(Input.TextArea, {
6288
+ value: editableResponseContent[ep.id] ?? "",
6289
+ onChange: (e) => {
6290
+ setEditableResponseContent((prev) => ({
6291
+ ...prev,
6292
+ [ep.id]: e.target.value
6293
+ }));
6294
+ onResponseContentChange?.(ep.id, e.target.value);
6295
+ },
6296
+ rows: Math.max(3, (editableResponseContent[ep.id] ?? "").split("\n").length),
6297
+ style: {
6298
+ fontFamily: "monospace",
6299
+ fontSize: "0.75rem",
6300
+ background: "#1D2856",
6301
+ color: "#fff",
6302
+ outline: "none",
6303
+ boxShadow: "none",
6304
+ border: "none"
6305
+ }
6198
6306
  }), /* @__PURE__ */ jsxs("div", {
6199
6307
  className: cx("code-footer"),
6200
6308
  children: [/* @__PURE__ */ jsx(Button, {
6201
6309
  ghost: true,
6202
6310
  size: "small",
6203
6311
  className: cx("code-btn"),
6312
+ onClick: () => handleValidate(editableResponseContent[ep.id] ?? ""),
6204
6313
  children: "Validate"
6205
6314
  }), /* @__PURE__ */ jsx(Button, {
6206
6315
  ghost: true,
6207
6316
  size: "small",
6208
6317
  className: cx("code-btn"),
6318
+ onClick: () => handleBeautify(editableResponseContent[ep.id] ?? "", (v) => setEditableResponseContent((prev) => ({
6319
+ ...prev,
6320
+ [ep.id]: v
6321
+ }))),
6209
6322
  children: "Beautify"
6210
6323
  })]
6211
6324
  })]
@@ -6354,7 +6467,8 @@ const EndpointsSection = ({ endpointsByTag, collapsed = false, onToggleCollapse,
6354
6467
  setParamDrawerEndpointId(null);
6355
6468
  setParamDrawerMode("add");
6356
6469
  setEditParamIdx(null);
6357
- }
6470
+ },
6471
+ source: drawerSource
6358
6472
  })
6359
6473
  ]
6360
6474
  }));
@@ -6856,9 +6970,9 @@ const TagsSection = ({ tags, collapsed, onToggleCollapse, onAddTag, onEditTag, o
6856
6970
  };
6857
6971
  //#endregion
6858
6972
  //#region src/view/components/ApiPage/components/AddTagDrawer.tsx
6859
- const TAG_NAME_REGEX = /^[A-Za-z0-9_-]+$/;
6860
- const TAG_DESC_REGEX = /^[A-Za-z0-9_-]+$/;
6861
- const EXT_DESC_REGEX = /^[A-Za-z0-9_-]+$/;
6973
+ const TAG_NAME_REGEX = /^[A-Za-z0-9_\s-]+$/;
6974
+ const TAG_DESC_REGEX = /^[A-Za-z0-9_\s-]+$/;
6975
+ const EXTERNAL_DOCS_DESC_REGEX = /^[A-Za-z0-9_\s-]+$/;
6862
6976
  const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag }) => {
6863
6977
  const [form] = Form.useForm();
6864
6978
  const [messageApi, contextHolder] = message.useMessage();
@@ -7099,7 +7213,7 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7099
7213
  },
7100
7214
  {
7101
7215
  pattern: TAG_NAME_REGEX,
7102
- message: "Only letters, numbers, underscores, and hyphens"
7216
+ message: "Only letters, numbers, spaces, underscores, and hyphens"
7103
7217
  }
7104
7218
  ],
7105
7219
  children: /* @__PURE__ */ jsx(Input, {
@@ -7120,10 +7234,10 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7120
7234
  rules: [{
7121
7235
  max: 50,
7122
7236
  message: "Maximum 50 characters"
7123
- }, { validator: (_, value) => {
7124
- if (!value || TAG_DESC_REGEX.test(value)) return Promise.resolve();
7125
- return Promise.reject(/* @__PURE__ */ new Error("Only letters, numbers, underscores, and hyphens"));
7126
- } }],
7237
+ }, {
7238
+ pattern: TAG_DESC_REGEX,
7239
+ message: "Only letters, numbers, spaces, _ and - allowed"
7240
+ }],
7127
7241
  children: /* @__PURE__ */ jsx(Input.TextArea, {
7128
7242
  showCount: true,
7129
7243
  maxLength: 50,
@@ -7143,10 +7257,10 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7143
7257
  rules: [{
7144
7258
  max: 25,
7145
7259
  message: "Maximum 25 characters"
7146
- }, { validator: (_, value) => {
7147
- if (!value || EXT_DESC_REGEX.test(value)) return Promise.resolve();
7148
- return Promise.reject(/* @__PURE__ */ new Error("Only letters, numbers, underscores, and hyphens"));
7149
- } }],
7260
+ }, {
7261
+ pattern: EXTERNAL_DOCS_DESC_REGEX,
7262
+ message: "Only letters, numbers, spaces, _ and - allowed"
7263
+ }],
7150
7264
  children: /* @__PURE__ */ jsx(Input, {
7151
7265
  showCount: true,
7152
7266
  maxLength: 25,
@@ -7168,8 +7282,8 @@ const AddTagDrawer = ({ open, onClose, mode, initialValues, onAddTag, onEditTag
7168
7282
  children: "External Docs Link"
7169
7283
  }),
7170
7284
  rules: [{
7171
- max: 512,
7172
- message: "Maximum 512 characters"
7285
+ max: 500,
7286
+ message: "Maximum 500 characters"
7173
7287
  }, { validator: async () => {
7174
7288
  const desc = form.getFieldValue("externalDocsDescription");
7175
7289
  const link = form.getFieldValue("externalDocsLink");
@@ -8505,7 +8619,7 @@ const Codebox$1 = ({ code, language, wrapLongLines }) => {
8505
8619
  //#endregion
8506
8620
  //#region src/view/console/CodeboxSidebar.tsx
8507
8621
  function CodeboxSidebar$1() {
8508
- const { selectedEndpoint, selectedApi, activeRequestTab, selectedStatusCode, statusCodeOptions, setSelectedStatusCode } = useStore(({ view }) => view);
8622
+ const { selectedEndpoint, selectedApi, selectedStatusCode, statusCodeOptions, setSelectedStatusCode } = useStore(({ view }) => view);
8509
8623
  const httpStatusOptions = useMemo(() => statusCodeOptions.map((code) => ({
8510
8624
  value: code,
8511
8625
  label: /* @__PURE__ */ jsxs("span", {
@@ -8538,7 +8652,7 @@ function CodeboxSidebar$1() {
8538
8652
  const queryParams = params.filter((p) => p.in === "query");
8539
8653
  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'`)];
8540
8654
  })();
8541
- const hasActiveTabParams = (selectedEndpoint?.parameters ?? []).some((p) => p.in === activeRequestTab);
8655
+ const hasAnyParams = (selectedEndpoint?.parameters ?? []).some((p) => p.in === "header" || p.in === "path" || p.in === "query");
8542
8656
  const { token: antdToken, theme: themeConfig } = theme.useToken();
8543
8657
  const isDark = themeConfig.id == 1;
8544
8658
  const headerBg = isDark ? antdToken.colorBgElevated : "#1d2856";
@@ -8660,7 +8774,7 @@ function CodeboxSidebar$1() {
8660
8774
  }));
8661
8775
  return /* @__PURE__ */ jsxs("div", {
8662
8776
  className: cx("container"),
8663
- children: [hasActiveTabParams && /* @__PURE__ */ jsxs("div", {
8777
+ children: [hasAnyParams && /* @__PURE__ */ jsxs("div", {
8664
8778
  className: cx("rightCard", "rightCardRequest"),
8665
8779
  children: [/* @__PURE__ */ jsxs("div", {
8666
8780
  className: cx("rightCardHeader"),
@@ -8715,6 +8829,15 @@ function CodeboxSidebar$1() {
8715
8829
  }
8716
8830
  //#endregion
8717
8831
  //#region src/view/helper/mutate.ts
8832
+ /**
8833
+ * Simple deterministic string hash (djb2 variant).
8834
+ * Produces a stable, short base-36 hash for the same input.
8835
+ */
8836
+ const stableHash = (input) => {
8837
+ let hash = 5381;
8838
+ for (let i = 0; i < input.length; i++) hash = (hash << 5) + hash + input.charCodeAt(i);
8839
+ return (hash >>> 0).toString(36);
8840
+ };
8718
8841
  const resolveSchema = (schema, components) => {
8719
8842
  if (!schema) return void 0;
8720
8843
  if (!schema.$ref) return schema;
@@ -8777,14 +8900,14 @@ const transformOpenApiToDocs = (api) => {
8777
8900
  if (!groupedPathsByTags[tag]) groupedPathsByTags[tag] = [];
8778
8901
  groupedPathsByTags[tag].push({
8779
8902
  ...entry,
8780
- id: `endpoint-${nanoid(8)}`
8903
+ id: `endpoint-${stableHash(entry.method + "-" + entry.path)}`
8781
8904
  });
8782
8905
  });
8783
8906
  else {
8784
8907
  if (!groupedPathsByTags.default) groupedPathsByTags.default = [];
8785
8908
  groupedPathsByTags.default.push({
8786
8909
  ...entry,
8787
- id: `endpoint-${nanoid(8)}`
8910
+ id: `endpoint-${stableHash(entry.method + "-" + entry.path)}`
8788
8911
  });
8789
8912
  }
8790
8913
  }
@@ -8798,7 +8921,7 @@ const transformOpenApiToDocs = (api) => {
8798
8921
  }, {});
8799
8922
  return {
8800
8923
  ...api.info,
8801
- id: `api-${nanoid(8)}`,
8924
+ id: `api-${contextPath ?? "unknown"}`,
8802
8925
  contextPath,
8803
8926
  tags: sortedGroupedPathsByTags,
8804
8927
  servers: api.servers,
@@ -8827,7 +8950,7 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8827
8950
  const [apiNameTouched, setApiNameTouched] = useState(false);
8828
8951
  const [localDescription, setLocalDescription] = useState("");
8829
8952
  const [descriptionTouched, setDescriptionTouched] = useState(false);
8830
- const hasApiNameError = apiNameTouched && (!localApiName.trim() || !/^[A-Za-z0-9_-]+$/.test(localApiName.trim()));
8953
+ const hasApiNameError = apiNameTouched && (!localApiName.trim() || !/^[A-Za-z0-9_\s-]+$/.test(localApiName.trim()));
8831
8954
  const hasDescriptionError = descriptionTouched && !localDescription.trim();
8832
8955
  const hasGeneralError = hasApiNameError || hasDescriptionError;
8833
8956
  const [saveErrors, setSaveErrors] = useState([]);
@@ -8837,6 +8960,8 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8837
8960
  const [endpointTags, setEndpointTags] = useState({});
8838
8961
  const [endpointParams, setEndpointParams] = useState({});
8839
8962
  const [endpointResponseParams, setEndpointResponseParams] = useState({});
8963
+ const [endpointRequestBody, setEndpointRequestBody] = useState({});
8964
+ const [endpointResponseBody, setEndpointResponseBody] = useState({});
8840
8965
  const [tagDrawerState, setTagDrawerState] = useState({
8841
8966
  open: false,
8842
8967
  mode: "add"
@@ -8847,7 +8972,7 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
8847
8972
  });
8848
8973
  const [localTags, setLocalTags] = useState([]);
8849
8974
  const [messageApi, contextHolder] = message.useMessage();
8850
- const { focusedContent, selectedNodeKey, selectedApi, originalData, builtTreeData, selectedEndpoint, setOriginalData, setTransformedData, setBuiltTreeData, setFocusedContent, setExpandedKeys, setSelectedEndpoint } = useStore(({ view }) => view);
8975
+ const { focusedContent, selectedNodeKey, selectedApi, originalData, transformedData, builtTreeData, selectedEndpoint, setOriginalData, setTransformedData, setBuiltTreeData, setSelectedApi, setFocusedContent, setExpandedKeys, setSelectedEndpoint } = useStore(({ view }) => view);
8851
8976
  const { selectFirstApi, selectPreSelectedApi, clearSelection } = useNodeSelection();
8852
8977
  const hasInitializedRef = useRef(false);
8853
8978
  const { useBreakpoint } = Grid;
@@ -9071,10 +9196,50 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9071
9196
  });
9072
9197
  return result;
9073
9198
  }, [originalData, selectedApi]);
9199
+ const initialEndpointRequestBody = useMemo(() => {
9200
+ if (!originalData || !selectedApi) return {};
9201
+ const rawFile = originalData.find((f) => Object.keys(f.paths)[0] === selectedApi.contextPath);
9202
+ if (!rawFile) return {};
9203
+ const pathMethodToId = {};
9204
+ Object.values(selectedApi.tags).flat().forEach((ep) => {
9205
+ pathMethodToId[`${ep.path}||${ep.method.toLowerCase()}`] = ep.id;
9206
+ });
9207
+ const result = {};
9208
+ Object.entries(rawFile.paths).forEach(([path, methods]) => {
9209
+ Object.entries(methods).forEach(([method, operation]) => {
9210
+ const schema = operation.requestBody?.content?.["application/json"]?.schema;
9211
+ const epId = pathMethodToId[`${path}||${method}`];
9212
+ if (epId && schema) result[epId] = schema;
9213
+ });
9214
+ });
9215
+ return result;
9216
+ }, [originalData, selectedApi]);
9217
+ const initialEndpointResponseBody = useMemo(() => {
9218
+ if (!originalData || !selectedApi) return {};
9219
+ const rawFile = originalData.find((f) => Object.keys(f.paths)[0] === selectedApi.contextPath);
9220
+ if (!rawFile) return {};
9221
+ const pathMethodToId = {};
9222
+ Object.values(selectedApi.tags).flat().forEach((ep) => {
9223
+ pathMethodToId[`${ep.path}||${ep.method.toLowerCase()}`] = ep.id;
9224
+ });
9225
+ const result = {};
9226
+ Object.entries(rawFile.paths).forEach(([path, methods]) => {
9227
+ Object.entries(methods).forEach(([method, operation]) => {
9228
+ const responses = operation.responses;
9229
+ if (!responses) return;
9230
+ const schema = responses["200" in responses ? "200" : Object.keys(responses)[0]]?.content?.["application/json"]?.schema;
9231
+ const epId = pathMethodToId[`${path}||${method}`];
9232
+ if (epId && schema) result[epId] = schema;
9233
+ });
9234
+ });
9235
+ return result;
9236
+ }, [originalData, selectedApi]);
9074
9237
  useEffect(() => {
9075
9238
  setLocalTags(tagMetadata);
9076
9239
  setEndpointParams(initialEndpointParams);
9077
9240
  setEndpointResponseParams(initialEndpointResponseParams);
9241
+ setEndpointRequestBody(initialEndpointRequestBody);
9242
+ setEndpointResponseBody(initialEndpointResponseBody);
9078
9243
  }, [selectedApi]);
9079
9244
  const hasChanges = useMemo(() => {
9080
9245
  if (!selectedApi) return false;
@@ -9289,11 +9454,45 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9289
9454
  else delete methodObj["x-response-params"];
9290
9455
  }
9291
9456
  });
9457
+ Object.entries(endpointRequestBody).forEach(([id, schema]) => {
9458
+ const loc = idToPathMethod[id];
9459
+ if (!loc) return;
9460
+ const pathEntry = cloned.paths[loc.path];
9461
+ if (!pathEntry) return;
9462
+ const methodObj = pathEntry[loc.method];
9463
+ if (!methodObj) return;
9464
+ const methodObjAny = methodObj;
9465
+ if (!methodObjAny.requestBody) methodObjAny.requestBody = {};
9466
+ const rb = methodObjAny.requestBody;
9467
+ if (!rb.content) rb.content = {};
9468
+ rb.content["application/json"] = { schema };
9469
+ });
9470
+ Object.entries(endpointResponseBody).forEach(([id, schema]) => {
9471
+ const loc = idToPathMethod[id];
9472
+ if (!loc) return;
9473
+ const pathEntry = cloned.paths[loc.path];
9474
+ if (!pathEntry) return;
9475
+ const methodObj = pathEntry[loc.method];
9476
+ if (!methodObj) return;
9477
+ const methodObjAny = methodObj;
9478
+ if (!methodObjAny.responses) return;
9479
+ const responses = methodObjAny.responses;
9480
+ const statusCode = "200" in responses ? "200" : Object.keys(responses)[0];
9481
+ if (!responses[statusCode]) return;
9482
+ if (!responses[statusCode].content) responses[statusCode].content = {};
9483
+ responses[statusCode].content["application/json"] = { schema };
9484
+ });
9292
9485
  try {
9293
9486
  await onSave?.(cloned);
9294
9487
  setBannerVisible(false);
9295
9488
  setSaveErrors([]);
9296
9489
  messageApi.success("Changes have been saved and published successfully.");
9490
+ setOriginalData(originalData.map((f) => Object.keys(f.paths)[0] === selectedApi.contextPath ? cloned : f));
9491
+ const newTransformed = [cloned].map(transformOpenApiToDocs)[0];
9492
+ const newTransformedData = (transformedData ?? []).map((t) => t.contextPath === selectedApi.contextPath ? newTransformed : t);
9493
+ setTransformedData(newTransformedData);
9494
+ setBuiltTreeData(buildTreeDataStructure(newTransformedData) ?? []);
9495
+ setSelectedApi(newTransformed);
9297
9496
  } catch (err) {
9298
9497
  let messages = [];
9299
9498
  if (err && typeof err === "object" && "errors" in err) {
@@ -9628,7 +9827,29 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9628
9827
  [endpointId]: prev[endpointId]?.filter((_, i) => i !== idx) ?? []
9629
9828
  }));
9630
9829
  setBannerVisible(true);
9631
- }
9830
+ },
9831
+ onRequestContentChange: (endpointId, jsonString) => {
9832
+ try {
9833
+ const schema = JSON.parse(jsonString);
9834
+ setEndpointRequestBody((prev) => ({
9835
+ ...prev,
9836
+ [endpointId]: schema
9837
+ }));
9838
+ setBannerVisible(true);
9839
+ } catch {}
9840
+ },
9841
+ onResponseContentChange: (endpointId, jsonString) => {
9842
+ try {
9843
+ const schema = JSON.parse(jsonString);
9844
+ setEndpointResponseBody((prev) => ({
9845
+ ...prev,
9846
+ [endpointId]: schema
9847
+ }));
9848
+ setBannerVisible(true);
9849
+ } catch {}
9850
+ },
9851
+ requestBodySchemas: endpointRequestBody,
9852
+ responseBodySchemas: endpointResponseBody
9632
9853
  }, resetKey)
9633
9854
  })
9634
9855
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -9767,7 +9988,29 @@ const ConsoleDocumentationLayout = ({ data, preSelectedApi, handleVisitLandingPa
9767
9988
  [endpointId]: prev[endpointId]?.filter((_, i) => i !== idx) ?? []
9768
9989
  }));
9769
9990
  setBannerVisible(true);
9770
- }
9991
+ },
9992
+ onRequestContentChange: (endpointId, jsonString) => {
9993
+ try {
9994
+ const schema = JSON.parse(jsonString);
9995
+ setEndpointRequestBody((prev) => ({
9996
+ ...prev,
9997
+ [endpointId]: schema
9998
+ }));
9999
+ setBannerVisible(true);
10000
+ } catch {}
10001
+ },
10002
+ onResponseContentChange: (endpointId, jsonString) => {
10003
+ try {
10004
+ const schema = JSON.parse(jsonString);
10005
+ setEndpointResponseBody((prev) => ({
10006
+ ...prev,
10007
+ [endpointId]: schema
10008
+ }));
10009
+ setBannerVisible(true);
10010
+ } catch {}
10011
+ },
10012
+ requestBodySchemas: endpointRequestBody,
10013
+ responseBodySchemas: endpointResponseBody
9771
10014
  }, resetKey)
9772
10015
  ] })
9773
10016
  })]