drf-to-mkdoc 0.2.3__py3-none-any.whl → 0.3.0__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/conf/settings.py +1 -0
- drf_to_mkdoc/management/commands/build_model_docs.py +10 -1
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/field-sections-loader.js +29 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/query-parameters-loader.js +16 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/field-extractor.js +200 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/form-manager.js +307 -14
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/main.js +39 -11
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/modal.js +298 -18
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/query-parameters-extractor.js +94 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/request-executor.js +278 -62
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/response-modal.js +173 -0
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/suggestions.js +59 -152
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/tabs.js +52 -9
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/badges.css +13 -5
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/theme-toggle.css +297 -25
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/fab.css +204 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/response.css +323 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out/variables.css +139 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/field-sections.css +136 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/form.css +539 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/modal.css +239 -17
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/response.css +503 -43
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/tabs.css +71 -19
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/variables.css +71 -15
- drf_to_mkdoc/templates/endpoints/detail/request_body.html +2 -0
- drf_to_mkdoc/templates/er_diagrams/app.html +26 -0
- drf_to_mkdoc/templates/er_diagrams/index.html +14 -0
- drf_to_mkdoc/templates/er_diagrams/main.html +22 -0
- drf_to_mkdoc/templates/try-out/fab.html +67 -3
- drf_to_mkdoc/templates/try-out/form.html +221 -74
- drf_to_mkdoc/templates/try-out/modal.html +75 -7
- drf_to_mkdoc/templates/try-out/response-modal.html +138 -9
- drf_to_mkdoc/utils/endpoint_detail_generator.py +1 -0
- drf_to_mkdoc/utils/er_diagram_generator.py +230 -0
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/METADATA +89 -10
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/RECORD +40 -27
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/WHEEL +0 -0
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {drf_to_mkdoc-0.2.3.dist-info → drf_to_mkdoc-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -2,22 +2,30 @@
|
|
|
2
2
|
const TryOutSuggestions = {
|
|
3
3
|
init: function() {
|
|
4
4
|
this.suggestions = this.getAvailableSuggestions();
|
|
5
|
-
this.
|
|
5
|
+
this.updateDatalist();
|
|
6
|
+
|
|
7
|
+
// Re-initialize when window.queryParametersData changes
|
|
8
|
+
if (window.MutationObserver) {
|
|
9
|
+
this.setupDataObserver();
|
|
10
|
+
}
|
|
6
11
|
},
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
this.
|
|
12
|
+
|
|
13
|
+
setupDataObserver: function() {
|
|
14
|
+
// Check for changes in queryParametersData every second
|
|
15
|
+
setInterval(() => {
|
|
16
|
+
if (window.queryParametersData && window.queryParametersData._lastUpdate !== this._lastDataUpdate) {
|
|
17
|
+
this._lastDataUpdate = window.queryParametersData._lastUpdate;
|
|
18
|
+
this.suggestions = this.getAvailableSuggestions();
|
|
19
|
+
this.updateDatalist();
|
|
14
20
|
}
|
|
15
|
-
});
|
|
21
|
+
}, 1000);
|
|
22
|
+
},
|
|
16
23
|
|
|
17
|
-
|
|
24
|
+
setupAutocomplete: function() {
|
|
25
|
+
// Using native datalist, just make sure all inputs are properly initialized
|
|
18
26
|
this.setupExistingInputs();
|
|
19
|
-
|
|
20
|
-
// Setup for the add button to
|
|
27
|
+
|
|
28
|
+
// Setup for the add button to mark new inputs as initialized
|
|
21
29
|
const addBtn = document.querySelector('.add-btn');
|
|
22
30
|
if (addBtn) {
|
|
23
31
|
addBtn.addEventListener('click', () => {
|
|
@@ -28,10 +36,27 @@ const TryOutSuggestions = {
|
|
|
28
36
|
});
|
|
29
37
|
}
|
|
30
38
|
},
|
|
39
|
+
|
|
40
|
+
updateDatalist: function() {
|
|
41
|
+
// Update the datalist with our suggestions
|
|
42
|
+
const datalist = document.getElementById('paramSuggestions');
|
|
43
|
+
if (datalist && this.suggestions.length > 0) {
|
|
44
|
+
// Clear existing options
|
|
45
|
+
datalist.innerHTML = '';
|
|
46
|
+
|
|
47
|
+
// Add new options from our suggestions - without descriptions
|
|
48
|
+
this.suggestions.forEach(suggestion => {
|
|
49
|
+
const option = document.createElement('option');
|
|
50
|
+
option.value = suggestion.name;
|
|
51
|
+
// No description text as per requirement
|
|
52
|
+
datalist.appendChild(option);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
},
|
|
31
56
|
|
|
32
57
|
setupExistingInputs: function() {
|
|
33
58
|
// Find all parameter name inputs
|
|
34
|
-
const paramInputs = document.querySelectorAll('#queryParams .
|
|
59
|
+
const paramInputs = document.querySelectorAll('#queryParams .name-input');
|
|
35
60
|
paramInputs.forEach(input => {
|
|
36
61
|
// Skip if already initialized
|
|
37
62
|
if (input.dataset.autocompleteInitialized) return;
|
|
@@ -39,177 +64,59 @@ const TryOutSuggestions = {
|
|
|
39
64
|
// Mark as initialized
|
|
40
65
|
input.dataset.autocompleteInitialized = 'true';
|
|
41
66
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
suggestionsContainer.className = 'param-suggestions';
|
|
45
|
-
suggestionsContainer.id = 'suggestions-' + Math.random().toString(36).substr(2, 9);
|
|
46
|
-
input.parentNode.style.position = 'relative';
|
|
47
|
-
input.parentNode.appendChild(suggestionsContainer);
|
|
48
|
-
|
|
49
|
-
// Store reference to container
|
|
50
|
-
input.dataset.suggestionsContainer = suggestionsContainer.id;
|
|
51
|
-
|
|
52
|
-
// Add event listeners
|
|
53
|
-
input.addEventListener('focus', () => this.showSuggestions(input));
|
|
54
|
-
input.addEventListener('input', () => this.filterSuggestions(input));
|
|
55
|
-
input.addEventListener('keydown', (e) => this.handleKeyNavigation(e, input));
|
|
67
|
+
// We're using the native datalist for autocomplete
|
|
68
|
+
// No need for custom suggestions dropdown
|
|
56
69
|
});
|
|
57
70
|
},
|
|
58
71
|
|
|
59
72
|
getAvailableSuggestions: function() {
|
|
73
|
+
// Get query parameters only from window.queryParametersData
|
|
60
74
|
const suggestions = [];
|
|
61
75
|
|
|
62
|
-
// Try to get query parameters from the page context
|
|
63
76
|
if (window.queryParametersData) {
|
|
64
77
|
const data = window.queryParametersData;
|
|
65
78
|
|
|
66
79
|
// Add filter fields
|
|
67
80
|
if (data.filter_fields && data.filter_fields.length > 0) {
|
|
68
|
-
suggestions.push(...data.filter_fields
|
|
81
|
+
suggestions.push(...data.filter_fields.map(field => ({
|
|
82
|
+
name: field
|
|
83
|
+
})));
|
|
69
84
|
}
|
|
70
85
|
|
|
71
|
-
// Add search
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
86
|
+
// Add search fields - only add the 'search' key, not individual fields
|
|
87
|
+
// The 'search' key will be added via special_keys
|
|
88
|
+
|
|
89
|
+
// Add ordering fields - only add the 'ordering' key, not individual fields
|
|
90
|
+
// The 'ordering' key will be added via special_keys
|
|
75
91
|
|
|
76
|
-
// Add
|
|
77
|
-
if (data.
|
|
78
|
-
suggestions.push(
|
|
92
|
+
// Add special keys
|
|
93
|
+
if (data.special_keys && data.special_keys.length > 0) {
|
|
94
|
+
suggestions.push(...data.special_keys.map(key => ({
|
|
95
|
+
name: key
|
|
96
|
+
})));
|
|
79
97
|
}
|
|
80
98
|
|
|
81
|
-
// Add pagination
|
|
99
|
+
// Add pagination fields
|
|
82
100
|
if (data.pagination_fields && data.pagination_fields.length > 0) {
|
|
83
|
-
suggestions.push(...data.pagination_fields
|
|
101
|
+
suggestions.push(...data.pagination_fields.map(field => ({
|
|
102
|
+
name: field
|
|
103
|
+
})));
|
|
84
104
|
}
|
|
85
105
|
}
|
|
86
106
|
|
|
87
|
-
|
|
88
|
-
if (suggestions.length === 0) {
|
|
89
|
-
suggestions.push('search', 'ordering', 'page', 'page_size');
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Remove duplicates and return
|
|
93
|
-
return [...new Set(suggestions)];
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
showSuggestions: function(input) {
|
|
97
|
-
const container = document.getElementById(input.dataset.suggestionsContainer);
|
|
98
|
-
if (!container) return;
|
|
99
|
-
|
|
100
|
-
// Clear existing suggestions
|
|
101
|
-
container.innerHTML = '';
|
|
102
|
-
|
|
103
|
-
// Filter suggestions based on input value
|
|
104
|
-
const inputValue = input.value.toLowerCase();
|
|
105
|
-
const filteredSuggestions = this.suggestions.filter(suggestion =>
|
|
106
|
-
suggestion.toLowerCase().includes(inputValue)
|
|
107
|
-
);
|
|
108
|
-
|
|
109
|
-
if (filteredSuggestions.length === 0) {
|
|
110
|
-
container.classList.remove('show');
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Add suggestions to container
|
|
115
|
-
filteredSuggestions.forEach(suggestion => {
|
|
116
|
-
const suggestionElement = document.createElement('div');
|
|
117
|
-
suggestionElement.className = 'param-suggestion';
|
|
118
|
-
suggestionElement.textContent = suggestion;
|
|
119
|
-
suggestionElement.addEventListener('click', (e) => {
|
|
120
|
-
e.stopPropagation();
|
|
121
|
-
this.selectSuggestion(input, suggestion);
|
|
122
|
-
});
|
|
123
|
-
container.appendChild(suggestionElement);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// Show suggestions
|
|
127
|
-
container.classList.add('show');
|
|
128
|
-
},
|
|
129
|
-
|
|
130
|
-
filterSuggestions: function(input) {
|
|
131
|
-
// Just re-show suggestions with current filter
|
|
132
|
-
this.showSuggestions(input);
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
hideAllSuggestions: function() {
|
|
136
|
-
document.querySelectorAll('.param-suggestions').forEach(container => {
|
|
137
|
-
container.classList.remove('show');
|
|
138
|
-
});
|
|
107
|
+
return suggestions;
|
|
139
108
|
},
|
|
140
109
|
|
|
141
110
|
selectSuggestion: function(input, suggestion) {
|
|
142
111
|
// Set input value
|
|
143
112
|
input.value = suggestion;
|
|
144
113
|
|
|
145
|
-
// Hide suggestions
|
|
146
|
-
const container = document.getElementById(input.dataset.suggestionsContainer);
|
|
147
|
-
if (container) {
|
|
148
|
-
container.classList.remove('show');
|
|
149
|
-
}
|
|
150
|
-
|
|
151
114
|
// Focus on value input
|
|
152
115
|
const valueInput = input.nextElementSibling;
|
|
153
116
|
if (valueInput) {
|
|
154
117
|
valueInput.focus();
|
|
155
118
|
}
|
|
156
119
|
},
|
|
157
|
-
|
|
158
|
-
handleKeyNavigation: function(event, input) {
|
|
159
|
-
const container = document.getElementById(input.dataset.suggestionsContainer);
|
|
160
|
-
if (!container || !container.classList.contains('show')) return;
|
|
161
|
-
|
|
162
|
-
const suggestions = container.querySelectorAll('.param-suggestion');
|
|
163
|
-
if (suggestions.length === 0) return;
|
|
164
|
-
|
|
165
|
-
// Find currently selected suggestion
|
|
166
|
-
const selectedIndex = Array.from(suggestions).findIndex(el => el.classList.contains('selected'));
|
|
167
|
-
|
|
168
|
-
switch (event.key) {
|
|
169
|
-
case 'ArrowDown':
|
|
170
|
-
event.preventDefault();
|
|
171
|
-
this.navigateSuggestion(suggestions, selectedIndex, 1);
|
|
172
|
-
break;
|
|
173
|
-
|
|
174
|
-
case 'ArrowUp':
|
|
175
|
-
event.preventDefault();
|
|
176
|
-
this.navigateSuggestion(suggestions, selectedIndex, -1);
|
|
177
|
-
break;
|
|
178
|
-
|
|
179
|
-
case 'Enter':
|
|
180
|
-
event.preventDefault();
|
|
181
|
-
if (selectedIndex >= 0) {
|
|
182
|
-
this.selectSuggestion(input, suggestions[selectedIndex].textContent);
|
|
183
|
-
} else if (suggestions.length > 0) {
|
|
184
|
-
this.selectSuggestion(input, suggestions[0].textContent);
|
|
185
|
-
}
|
|
186
|
-
break;
|
|
187
|
-
|
|
188
|
-
case 'Escape':
|
|
189
|
-
event.preventDefault();
|
|
190
|
-
container.classList.remove('show');
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
|
|
195
|
-
navigateSuggestion: function(suggestions, currentIndex, direction) {
|
|
196
|
-
// Remove current selection
|
|
197
|
-
if (currentIndex >= 0) {
|
|
198
|
-
suggestions[currentIndex].classList.remove('selected');
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Calculate new index
|
|
202
|
-
let newIndex;
|
|
203
|
-
if (currentIndex < 0) {
|
|
204
|
-
newIndex = direction > 0 ? 0 : suggestions.length - 1;
|
|
205
|
-
} else {
|
|
206
|
-
newIndex = (currentIndex + direction + suggestions.length) % suggestions.length;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Select new suggestion
|
|
210
|
-
suggestions[newIndex].classList.add('selected');
|
|
211
|
-
suggestions[newIndex].scrollIntoView({ block: 'nearest' });
|
|
212
|
-
}
|
|
213
120
|
};
|
|
214
121
|
|
|
215
122
|
// Export for global access
|
|
@@ -1,33 +1,76 @@
|
|
|
1
1
|
// Tab management functionality
|
|
2
2
|
const TabManager = {
|
|
3
3
|
init: function() {
|
|
4
|
-
document.querySelectorAll('.try-out-form .tab').forEach(tab => {
|
|
4
|
+
document.querySelectorAll('.try-out-form .tab, .smart-tabs .tab, .response-tabs .tab').forEach(tab => {
|
|
5
5
|
tab.addEventListener('click', () => {
|
|
6
6
|
this.switchTab(tab);
|
|
7
7
|
});
|
|
8
|
+
|
|
9
|
+
// Add keyboard support
|
|
10
|
+
tab.addEventListener('keydown', (e) => {
|
|
11
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
12
|
+
e.preventDefault();
|
|
13
|
+
this.switchTab(tab);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
8
16
|
});
|
|
9
17
|
},
|
|
10
18
|
|
|
11
19
|
switchTab: function(activeTab) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
const tabContainer = activeTab.closest('.smart-tabs, .response-tabs, .try-out-form');
|
|
21
|
+
if (!tabContainer) return;
|
|
22
|
+
|
|
23
|
+
// Remove active class from all tabs in this container
|
|
24
|
+
tabContainer.querySelectorAll('.tab').forEach(t => {
|
|
25
|
+
t.classList.remove('active');
|
|
26
|
+
t.setAttribute('aria-selected', 'false');
|
|
27
|
+
});
|
|
15
28
|
|
|
16
|
-
//
|
|
29
|
+
// Remove active class from all tab content
|
|
30
|
+
const contentContainer = tabContainer.parentElement || document;
|
|
31
|
+
contentContainer.querySelectorAll('.tab-content').forEach(c => {
|
|
32
|
+
c.classList.remove('active');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Add active class to clicked tab and its content
|
|
17
36
|
activeTab.classList.add('active');
|
|
37
|
+
activeTab.setAttribute('aria-selected', 'true');
|
|
18
38
|
|
|
19
39
|
// Show corresponding content
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
40
|
+
const contentId = activeTab.getAttribute('aria-controls') || activeTab.getAttribute('data-tab');
|
|
41
|
+
let content;
|
|
42
|
+
|
|
43
|
+
if (contentId) {
|
|
44
|
+
content = document.getElementById(contentId) || document.getElementById(contentId + 'Tab');
|
|
45
|
+
if (content) {
|
|
46
|
+
content.classList.add('active');
|
|
47
|
+
}
|
|
24
48
|
}
|
|
49
|
+
|
|
50
|
+
// Debug logging
|
|
51
|
+
console.log('Tab switched to:', contentId, 'Content element:', content);
|
|
25
52
|
}
|
|
26
53
|
};
|
|
27
54
|
|
|
28
55
|
// Initialize tabs when DOM is ready
|
|
29
56
|
document.addEventListener('DOMContentLoaded', function() {
|
|
30
57
|
TabManager.init();
|
|
58
|
+
|
|
59
|
+
// Also initialize when modal is shown (for dynamic content)
|
|
60
|
+
const modal = document.getElementById('tryOutModal');
|
|
61
|
+
if (modal) {
|
|
62
|
+
const observer = new MutationObserver(function(mutations) {
|
|
63
|
+
mutations.forEach(function(mutation) {
|
|
64
|
+
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
|
65
|
+
if (modal.classList.contains('show')) {
|
|
66
|
+
// Re-initialize tabs when modal is shown
|
|
67
|
+
setTimeout(() => TabManager.init(), 100);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
observer.observe(modal, { attributes: true });
|
|
73
|
+
}
|
|
31
74
|
});
|
|
32
75
|
|
|
33
76
|
// Export for global access
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
/* ===== METHOD BADGES ===== */
|
|
2
2
|
.method-badge {
|
|
3
3
|
position: relative;
|
|
4
|
-
|
|
4
|
+
display: inline-block;
|
|
5
|
+
padding: 4px 8px;
|
|
5
6
|
font-size: 12px;
|
|
6
7
|
font-weight: bold;
|
|
7
|
-
border-radius:
|
|
8
|
+
border-radius: 16px;
|
|
8
9
|
color: white;
|
|
9
10
|
text-transform: uppercase;
|
|
10
11
|
overflow: hidden;
|
|
11
|
-
min-width:
|
|
12
|
+
min-width: 50px;
|
|
12
13
|
text-align: center;
|
|
13
14
|
flex-shrink: 0;
|
|
15
|
+
z-index: 0;
|
|
16
|
+
vertical-align: middle;
|
|
17
|
+
line-height: 1.2;
|
|
18
|
+
box-sizing: border-box;
|
|
19
|
+
white-space: nowrap;
|
|
14
20
|
}
|
|
15
21
|
|
|
16
22
|
.method-badge::before {
|
|
@@ -20,8 +26,10 @@
|
|
|
20
26
|
left: -100%;
|
|
21
27
|
width: 100%;
|
|
22
28
|
height: 100%;
|
|
23
|
-
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.
|
|
24
|
-
transition: left 0.
|
|
29
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent);
|
|
30
|
+
transition: left 0.6s ease;
|
|
31
|
+
z-index: 1;
|
|
32
|
+
pointer-events: none;
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
.method-badge:hover::before {
|