drf-to-mkdoc 0.2.2__py3-none-any.whl → 0.2.3__py3-none-any.whl
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.
Potentially problematic release.
This version of drf-to-mkdoc might be problematic. Click here for more details.
- drf_to_mkdoc/conf/defaults.py +1 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/form-manager.js +172 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/main.js +22 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/modal.js +79 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/request-executor.js +111 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/suggestions.js +216 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/tabs.js +34 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/buttons.css +71 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/fab.css +47 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/form.css +124 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/key-value.css +161 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/main.css +57 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/modal.css +112 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/response.css +158 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/tabs.css +62 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/variables.css +38 -0
- drf_to_mkdoc/templates/endpoints/detail/base.html +3 -1
- drf_to_mkdoc/templates/endpoints/detail/query_parameters.html +1 -8
- drf_to_mkdoc/templates/endpoints/detail/responses.html +4 -4
- drf_to_mkdoc/templates/try-out/fab.html +4 -0
- drf_to_mkdoc/templates/try-out/form.html +113 -0
- drf_to_mkdoc/templates/try-out/main.html +4 -0
- drf_to_mkdoc/templates/try-out/modal.html +14 -0
- drf_to_mkdoc/templates/try-out/response-modal.html +20 -0
- drf_to_mkdoc/templatetags/custom_filters.py +33 -1
- drf_to_mkdoc/utils/commons/schema_utils.py +5 -14
- drf_to_mkdoc/utils/endpoint_detail_generator.py +140 -21
- drf_to_mkdoc/utils/extractors/query_parameter_extractors.py +0 -15
- {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/METADATA +1 -1
- {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/RECORD +33 -15
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out-sidebar.js +0 -879
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out-sidebar.css +0 -728
- {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/WHEEL +0 -0
- {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/* Response Modal */
|
|
2
|
+
.response-modal {
|
|
3
|
+
position: fixed;
|
|
4
|
+
top: 0;
|
|
5
|
+
left: 0;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
z-index: var(--try-out-z-response);
|
|
9
|
+
display: none;
|
|
10
|
+
align-items: center;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
padding: var(--try-out-spacing-lg);
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.response-modal .modal-header {
|
|
17
|
+
padding: var(--try-out-spacing-lg) var(--try-out-spacing-xl);
|
|
18
|
+
background: linear-gradient(135deg, var(--try-out-primary), #1565c0);
|
|
19
|
+
color: white;
|
|
20
|
+
display: flex;
|
|
21
|
+
align-items: center;
|
|
22
|
+
gap: var(--try-out-spacing);
|
|
23
|
+
flex-shrink: 0;
|
|
24
|
+
position: relative;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.response-modal .modal-header h3 {
|
|
28
|
+
margin: 0;
|
|
29
|
+
font-size: var(--try-out-font-lg);
|
|
30
|
+
font-weight: 600;
|
|
31
|
+
flex-grow: 1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.response-modal .modal-close {
|
|
35
|
+
background: none;
|
|
36
|
+
border: none;
|
|
37
|
+
color: white;
|
|
38
|
+
cursor: pointer;
|
|
39
|
+
padding: var(--try-out-spacing-sm);
|
|
40
|
+
font-size: var(--try-out-font-lg);
|
|
41
|
+
line-height: 1;
|
|
42
|
+
border-radius: 50%;
|
|
43
|
+
width: 28px;
|
|
44
|
+
height: 28px;
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: center;
|
|
48
|
+
position: absolute;
|
|
49
|
+
right: var(--try-out-spacing);
|
|
50
|
+
top: 50%;
|
|
51
|
+
transform: translateY(-50%);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.response-modal .modal-close:hover {
|
|
55
|
+
background-color: rgba(255, 255, 255, 0.1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.response-modal .modal-body {
|
|
59
|
+
padding: var(--try-out-spacing-xl);
|
|
60
|
+
overflow-y: auto;
|
|
61
|
+
flex: 1;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.response-modal.show {
|
|
65
|
+
display: flex;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.response-modal .modal-content {
|
|
69
|
+
position: relative;
|
|
70
|
+
width: 100%;
|
|
71
|
+
max-width: 700px;
|
|
72
|
+
max-height: 85vh;
|
|
73
|
+
background-color: var(--try-out-bg);
|
|
74
|
+
border-radius: var(--try-out-border-radius-lg);
|
|
75
|
+
box-shadow: 0 8px 32px var(--try-out-shadow-strong);
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
z-index: 1;
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.response-modal .response-header {
|
|
83
|
+
margin-bottom: var(--try-out-spacing-lg);
|
|
84
|
+
padding: var(--try-out-spacing);
|
|
85
|
+
border-radius: var(--try-out-border-radius);
|
|
86
|
+
background-color: var(--try-out-surface);
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: var(--try-out-spacing);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.response-modal .status-badge {
|
|
93
|
+
padding: var(--try-out-spacing-sm) var(--try-out-spacing);
|
|
94
|
+
border-radius: var(--try-out-border-radius);
|
|
95
|
+
font-size: var(--try-out-font-sm);
|
|
96
|
+
font-weight: 600;
|
|
97
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.response-modal .status-200 {
|
|
101
|
+
background-color: var(--try-out-success);
|
|
102
|
+
color: white;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.response-modal .status-300 {
|
|
106
|
+
background-color: var(--try-out-info);
|
|
107
|
+
color: white;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.response-modal .status-400 {
|
|
111
|
+
background-color: var(--try-out-warning);
|
|
112
|
+
color: #212529;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.response-modal .status-500 {
|
|
116
|
+
background-color: var(--try-out-danger);
|
|
117
|
+
color: white;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.response-modal .response-body {
|
|
121
|
+
background-color: var(--try-out-surface);
|
|
122
|
+
padding: var(--try-out-spacing-lg);
|
|
123
|
+
border-radius: var(--try-out-border-radius);
|
|
124
|
+
overflow: auto;
|
|
125
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
126
|
+
white-space: pre-wrap;
|
|
127
|
+
font-size: var(--try-out-font-sm);
|
|
128
|
+
line-height: var(--try-out-line-height);
|
|
129
|
+
max-height: 300px;
|
|
130
|
+
border: 1px solid var(--try-out-border);
|
|
131
|
+
flex: 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.response-modal .response-info {
|
|
135
|
+
display: flex;
|
|
136
|
+
align-items: center;
|
|
137
|
+
gap: var(--try-out-spacing);
|
|
138
|
+
font-size: var(--try-out-font-base);
|
|
139
|
+
color: var(--try-out-text);
|
|
140
|
+
font-weight: 500;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Mobile Response Modal */
|
|
144
|
+
@media screen and (max-width: 768px) {
|
|
145
|
+
.response-modal {
|
|
146
|
+
padding: var(--try-out-spacing-sm);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.response-modal .modal-content {
|
|
150
|
+
max-width: none;
|
|
151
|
+
max-height: 90vh;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.response-modal .response-body {
|
|
155
|
+
font-size: 12px;
|
|
156
|
+
max-height: 250px;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/* Tabs */
|
|
2
|
+
.tabs {
|
|
3
|
+
display: flex;
|
|
4
|
+
gap: 0;
|
|
5
|
+
margin-bottom: var(--try-out-spacing-lg);
|
|
6
|
+
border: 1px solid var(--try-out-border);
|
|
7
|
+
border-radius: var(--try-out-border-radius);
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
background-color: var(--try-out-surface);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.tab {
|
|
13
|
+
flex: 1;
|
|
14
|
+
padding: var(--try-out-spacing) var(--try-out-spacing-lg);
|
|
15
|
+
border: none;
|
|
16
|
+
background: transparent;
|
|
17
|
+
color: var(--try-out-text-light);
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
font-size: var(--try-out-font-base);
|
|
20
|
+
font-weight: 500;
|
|
21
|
+
position: relative;
|
|
22
|
+
transition: var(--try-out-transition);
|
|
23
|
+
border-right: 1px solid var(--try-out-border);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.tab:last-child {
|
|
27
|
+
border-right: none;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.tab:hover {
|
|
31
|
+
background-color: rgba(25, 118, 210, 0.05);
|
|
32
|
+
color: var(--try-out-text);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.tab.active {
|
|
36
|
+
background-color: var(--try-out-primary);
|
|
37
|
+
color: white;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.tab-content {
|
|
41
|
+
display: none;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.tab-content.active {
|
|
45
|
+
display: block;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/* Mobile Tabs */
|
|
49
|
+
@media screen and (max-width: 768px) {
|
|
50
|
+
.tabs {
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.tab {
|
|
55
|
+
border-right: none;
|
|
56
|
+
border-bottom: 1px solid var(--try-out-border);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.tab:last-child {
|
|
60
|
+
border-bottom: none;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--try-out-primary: #1976d2;
|
|
3
|
+
--try-out-primary-hover: #1565c0;
|
|
4
|
+
--try-out-success: #28a745;
|
|
5
|
+
--try-out-success-hover: #218838;
|
|
6
|
+
--try-out-danger: #dc3545;
|
|
7
|
+
--try-out-danger-hover: #c82333;
|
|
8
|
+
--try-out-warning: #ffc107;
|
|
9
|
+
--try-out-info: #17a2b8;
|
|
10
|
+
|
|
11
|
+
--try-out-bg: #ffffff;
|
|
12
|
+
--try-out-surface: #f8f9fa;
|
|
13
|
+
--try-out-border: #e1e5e9;
|
|
14
|
+
--try-out-text: #333333;
|
|
15
|
+
--try-out-text-light: #666666;
|
|
16
|
+
--try-out-text-lighter: #999999;
|
|
17
|
+
--try-out-shadow: rgba(0, 0, 0, 0.1);
|
|
18
|
+
--try-out-shadow-strong: rgba(0, 0, 0, 0.2);
|
|
19
|
+
|
|
20
|
+
--try-out-border-radius: 4px;
|
|
21
|
+
--try-out-border-radius-lg: 6px;
|
|
22
|
+
--try-out-spacing-xs: 0.2rem;
|
|
23
|
+
--try-out-spacing-sm: 0.4rem;
|
|
24
|
+
--try-out-spacing: 0.6rem;
|
|
25
|
+
--try-out-spacing-lg: 0.8rem;
|
|
26
|
+
--try-out-spacing-xl: 1.2rem;
|
|
27
|
+
--try-out-spacing-xxl: 1.6rem;
|
|
28
|
+
|
|
29
|
+
--try-out-font-sm: 0.75rem;
|
|
30
|
+
--try-out-font-base: 0.8rem;
|
|
31
|
+
--try-out-font-lg: 0.9rem;
|
|
32
|
+
--try-out-line-height: 1.4;
|
|
33
|
+
|
|
34
|
+
--try-out-transition: all 0.2s ease;
|
|
35
|
+
--try-out-z-modal: 1000;
|
|
36
|
+
--try-out-z-response: 1100;
|
|
37
|
+
--try-out-z-fab: 100;
|
|
38
|
+
}
|
|
@@ -30,4 +30,6 @@
|
|
|
30
30
|
{% include "endpoints/detail/path_parameters.html" %}
|
|
31
31
|
{% include "endpoints/detail/query_parameters.html" %}
|
|
32
32
|
{% include "endpoints/detail/request_body.html" %}
|
|
33
|
-
{% include "endpoints/detail/responses.html" %}
|
|
33
|
+
{% include "endpoints/detail/responses.html" %}
|
|
34
|
+
|
|
35
|
+
{% include 'try-out/main.html' %}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Check if any query parameter fields have content
|
|
3
3
|
{% endcomment %}
|
|
4
4
|
|
|
5
|
-
{% if query_parameters.filter_fields or query_parameters.search_fields or query_parameters.ordering_fields or query_parameters.
|
|
5
|
+
{% if query_parameters.filter_fields or query_parameters.search_fields or query_parameters.ordering_fields or query_parameters.pagination_fields %}
|
|
6
6
|
## Query Parameters
|
|
7
7
|
|
|
8
8
|
{% if query_parameters.filter_fields %}
|
|
@@ -26,13 +26,6 @@ Check if any query parameter fields have content
|
|
|
26
26
|
{% endfor %}
|
|
27
27
|
{% endif %}
|
|
28
28
|
|
|
29
|
-
{% if query_parameters.filter_backends %}
|
|
30
|
-
### Filter Backends
|
|
31
|
-
{% for backend in query_parameters.filter_backends %}
|
|
32
|
-
- `{{ backend }}`
|
|
33
|
-
{% endfor %}
|
|
34
|
-
{% endif %}
|
|
35
|
-
|
|
36
29
|
{% if query_parameters.pagination_fields %}
|
|
37
30
|
### Pagination Fields
|
|
38
31
|
{% for field in query_parameters.pagination_fields %}
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
{{ response.description }}
|
|
11
11
|
{% endif %}
|
|
12
12
|
|
|
13
|
-
{%
|
|
14
|
-
{{
|
|
15
|
-
{%
|
|
13
|
+
{% for example in response.examples %}
|
|
14
|
+
{{ example|format_json }}
|
|
15
|
+
{% endfor %}
|
|
16
16
|
|
|
17
17
|
{% endfor %}
|
|
18
|
-
{% endif %}
|
|
18
|
+
{% endif %}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{% load custom_filters %}
|
|
2
|
+
|
|
3
|
+
<div class="try-out-form" data-method="{{ method }}">
|
|
4
|
+
<!-- Base URL Section -->
|
|
5
|
+
<div class="base-url-section">
|
|
6
|
+
<label for="baseUrl">Request URL</label>
|
|
7
|
+
<div class="url-display">
|
|
8
|
+
<input type="text" id="baseUrl" class="base-url-input" value="http://localhost:8000" placeholder="https://api.example.com">
|
|
9
|
+
<span class="path-display">{{ path }}</span>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<!-- Tabs -->
|
|
14
|
+
<div class="tabs">
|
|
15
|
+
<button class="tab active" data-tab="parameters">Parameters</button>
|
|
16
|
+
<button class="tab" data-tab="headers">Headers</button>
|
|
17
|
+
{% if method|upper in "POST,PUT,PATCH" %}
|
|
18
|
+
<button class="tab" data-tab="body">Request Body</button>
|
|
19
|
+
{% endif %}
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
<!-- Parameters Tab -->
|
|
23
|
+
<div class="tab-content active" id="parametersTab">
|
|
24
|
+
{% if path_params %}
|
|
25
|
+
<div class="form-group">
|
|
26
|
+
<label class="form-label">Path Parameters</label>
|
|
27
|
+
<div class="kv-container" id="pathParams">
|
|
28
|
+
{% for param in path_params %}
|
|
29
|
+
<div class="kv-item">
|
|
30
|
+
<label class="param-label{% if param.required %} required{% endif %}">{{ param.name }}</label>
|
|
31
|
+
<input type="text"
|
|
32
|
+
placeholder="Enter {{ param.name }} value"
|
|
33
|
+
data-param="{{ param.name }}"
|
|
34
|
+
{% if param.required %}required{% endif %}>
|
|
35
|
+
<div class="error-message"></div>
|
|
36
|
+
</div>
|
|
37
|
+
{% endfor %}
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
{% endif %}
|
|
41
|
+
|
|
42
|
+
<div class="form-group">
|
|
43
|
+
<label class="form-label">Query Parameters</label>
|
|
44
|
+
<div class="kv-container" id="queryParams">
|
|
45
|
+
<div class="kv-item">
|
|
46
|
+
<input type="text" placeholder="Parameter name">
|
|
47
|
+
<input type="text" placeholder="Parameter value">
|
|
48
|
+
<button class="remove-btn" onclick="TryOutSidebar.removeKvItem(this)">✕</button>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<button class="add-btn" onclick="TryOutSidebar.addQueryParam()">
|
|
52
|
+
<span>+</span> Add Parameter
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<!-- Headers Tab -->
|
|
58
|
+
<div class="tab-content" id="headersTab">
|
|
59
|
+
<div class="form-group">
|
|
60
|
+
<label class="form-label">Request Headers</label>
|
|
61
|
+
<div class="kv-container" id="requestHeaders">
|
|
62
|
+
<div class="kv-item">
|
|
63
|
+
<input type="text" value="Content-Type">
|
|
64
|
+
<input type="text" value="application/json">
|
|
65
|
+
<button class="remove-btn" onclick="TryOutSidebar.removeKvItem(this)">✕</button>
|
|
66
|
+
</div>
|
|
67
|
+
<div class="kv-item">
|
|
68
|
+
<input type="text" value="Authorization">
|
|
69
|
+
<input type="text" placeholder="Bearer your-token">
|
|
70
|
+
<button class="remove-btn" onclick="TryOutSidebar.removeKvItem(this)">✕</button>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
<button class="add-btn" onclick="TryOutSidebar.addHeader()">
|
|
74
|
+
<span>+</span> Add Header
|
|
75
|
+
</button>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<!-- Request Body Tab -->
|
|
80
|
+
{% if method|upper in "POST,PUT,PATCH" %}
|
|
81
|
+
<div class="tab-content" id="bodyTab">
|
|
82
|
+
<div class="form-group">
|
|
83
|
+
<label class="form-label">Request Body</label>
|
|
84
|
+
<textarea id="requestBody"
|
|
85
|
+
class="form-input form-textarea"
|
|
86
|
+
placeholder="Enter JSON request body..."
|
|
87
|
+
rows="8">{% if request_example %}{{ request_example|extract_json_from_markdown }}{% endif %}</textarea>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
{% endif %}
|
|
91
|
+
|
|
92
|
+
<!-- Execute Button -->
|
|
93
|
+
<button class="execute-btn" id="executeBtn" onclick="executeRequest()">
|
|
94
|
+
<span>▶</span> Execute Request
|
|
95
|
+
</button>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<script>
|
|
99
|
+
// Pass query parameters data to JavaScript
|
|
100
|
+
window.queryParametersData = {
|
|
101
|
+
{% if query_parameters %}
|
|
102
|
+
filter_fields: {{ query_parameters.filter_fields|default:"[]"|safe }},
|
|
103
|
+
search_fields: {{ query_parameters.search_fields|default:"[]"|safe }},
|
|
104
|
+
ordering_fields: {{ query_parameters.ordering_fields|default:"[]"|safe }},
|
|
105
|
+
pagination_fields: {{ query_parameters.pagination_fields|default:"[]"|safe }}
|
|
106
|
+
{% else %}
|
|
107
|
+
filter_fields: [],
|
|
108
|
+
search_fields: [],
|
|
109
|
+
ordering_fields: [],
|
|
110
|
+
pagination_fields: []
|
|
111
|
+
{% endif %}
|
|
112
|
+
};
|
|
113
|
+
</script>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!-- Try Out Modal -->
|
|
2
|
+
<div id="tryOutModal" class="try-out-modal" role="dialog" aria-modal="true" aria-label="Try It Out">
|
|
3
|
+
<div class="modal-overlay" onclick="TryOutSidebar.closeTryOut()"></div>
|
|
4
|
+
<div class="modal-content">
|
|
5
|
+
<div class="modal-header">
|
|
6
|
+
<span>🚀</span>
|
|
7
|
+
<h3>Try It Out</h3>
|
|
8
|
+
<button class="modal-close" aria-label="Close" onclick="TryOutSidebar.closeTryOut()">✕</button>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="modal-body">
|
|
11
|
+
{% include 'try-out/form.html' %}
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- Response Modal -->
|
|
2
|
+
<div id="responseModal" class="response-modal" role="dialog" aria-modal="true" aria-label="API Response">
|
|
3
|
+
<div class="modal-overlay" onclick="TryOutSidebar.closeResponseModal()"></div>
|
|
4
|
+
<div class="modal-content">
|
|
5
|
+
<div class="modal-header">
|
|
6
|
+
<h3>API Response</h3>
|
|
7
|
+
<button class="modal-close" aria-label="Close" onclick="TryOutSidebar.closeResponseModal()">✕</button>
|
|
8
|
+
</div>
|
|
9
|
+
<div class="modal-body">
|
|
10
|
+
<div class="response-header">
|
|
11
|
+
<div class="response-info">
|
|
12
|
+
<span>Status:</span>
|
|
13
|
+
<span class="status-badge" id="modalStatusBadge"></span>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="response-info" id="responseInfo"></div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="response-body" id="modalResponseBody"></div>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import html
|
|
2
2
|
import json
|
|
3
|
+
import re
|
|
3
4
|
|
|
4
5
|
from django import template
|
|
5
6
|
from django.templatetags.static import static as django_static
|
|
@@ -113,4 +114,35 @@ def format_json(value):
|
|
|
113
114
|
elif isinstance(value, dict | list):
|
|
114
115
|
value = json.dumps(value, indent=2)
|
|
115
116
|
|
|
116
|
-
return mark_safe(value) # noqa: S308
|
|
117
|
+
return mark_safe(f"```json\n{value}\n```") # noqa: S308
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@register.filter
|
|
121
|
+
def extract_json_from_markdown(value):
|
|
122
|
+
"""Extract JSON content from markdown code blocks"""
|
|
123
|
+
if not isinstance(value, str):
|
|
124
|
+
return ""
|
|
125
|
+
|
|
126
|
+
# Look for ```json code blocks
|
|
127
|
+
|
|
128
|
+
json_pattern = r"```json\s*\n(.*?)\n```"
|
|
129
|
+
matches = re.findall(json_pattern, value, re.DOTALL)
|
|
130
|
+
|
|
131
|
+
if matches:
|
|
132
|
+
return matches[0].strip()
|
|
133
|
+
|
|
134
|
+
# Fallback: look for any code block
|
|
135
|
+
code_pattern = r"```\s*\n(.*?)\n```"
|
|
136
|
+
matches = re.findall(code_pattern, value, re.DOTALL)
|
|
137
|
+
|
|
138
|
+
if matches:
|
|
139
|
+
content = matches[0].strip()
|
|
140
|
+
# Try to validate if it's JSON
|
|
141
|
+
try:
|
|
142
|
+
json.loads(content)
|
|
143
|
+
except (json.JSONDecodeError, TypeError):
|
|
144
|
+
pass
|
|
145
|
+
else:
|
|
146
|
+
return content
|
|
147
|
+
|
|
148
|
+
return ""
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from functools import lru_cache
|
|
2
4
|
from pathlib import Path
|
|
3
5
|
from typing import Any
|
|
4
6
|
|
|
5
|
-
import yaml
|
|
6
7
|
from drf_spectacular.generators import SchemaGenerator
|
|
7
8
|
|
|
8
9
|
from drf_to_mkdoc.conf.settings import drf_to_mkdoc_settings
|
|
@@ -21,16 +22,6 @@ class QueryParamTypeError(Exception):
|
|
|
21
22
|
pass
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
def load_schema() -> dict[str, Any] | None:
|
|
25
|
-
"""Load the OpenAPI schema from doc-schema.yaml"""
|
|
26
|
-
schema_file = Path(drf_to_mkdoc_settings.CONFIG_DIR) / "doc-schema.yaml"
|
|
27
|
-
if not schema_file.exists():
|
|
28
|
-
return None
|
|
29
|
-
|
|
30
|
-
with schema_file.open(encoding="utf-8") as f:
|
|
31
|
-
return yaml.safe_load(f)
|
|
32
|
-
|
|
33
|
-
|
|
34
25
|
def get_custom_schema():
|
|
35
26
|
custom_schema_data = load_json_data(
|
|
36
27
|
drf_to_mkdoc_settings.CUSTOM_SCHEMA_FILE, raise_not_found=False
|
|
@@ -56,7 +47,6 @@ def get_custom_schema():
|
|
|
56
47
|
"search_fields",
|
|
57
48
|
"filter_fields",
|
|
58
49
|
"ordering_fields",
|
|
59
|
-
"filter_backends",
|
|
60
50
|
"pagination_fields",
|
|
61
51
|
}
|
|
62
52
|
):
|
|
@@ -153,16 +143,17 @@ def _apply_custom_overrides(
|
|
|
153
143
|
target_schema[key] = custom_value
|
|
154
144
|
|
|
155
145
|
|
|
146
|
+
@lru_cache(maxsize=1)
|
|
156
147
|
def get_schema():
|
|
157
148
|
base_schema = SchemaGenerator().get_schema(request=None, public=True)
|
|
158
149
|
custom_data = get_custom_schema()
|
|
159
150
|
if not custom_data:
|
|
160
|
-
return base_schema
|
|
151
|
+
return deepcopy(base_schema)
|
|
161
152
|
|
|
162
153
|
operation_map = _build_operation_map(base_schema)
|
|
163
154
|
_apply_custom_overrides(base_schema, operation_map, custom_data)
|
|
164
155
|
|
|
165
|
-
return base_schema
|
|
156
|
+
return deepcopy(base_schema)
|
|
166
157
|
|
|
167
158
|
|
|
168
159
|
class OperationExtractor:
|